1688-cli 0.1.35 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/cart-add.js +5 -29
- package/dist/commands/cart-add.js.map +1 -1
- package/dist/commands/cart-remove.js +5 -61
- package/dist/commands/cart-remove.js.map +1 -1
- package/dist/commands/checkout-confirm.js +8 -83
- package/dist/commands/checkout-confirm.js.map +1 -1
- package/dist/commands/checkout-prepare.js +6 -63
- package/dist/commands/checkout-prepare.js.map +1 -1
- package/dist/commands/image-search.js +3 -26
- package/dist/commands/image-search.js.map +1 -1
- package/dist/commands/search.js +4 -14
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/seller-chat.js +6 -60
- package/dist/commands/seller-chat.js.map +1 -1
- package/dist/commands/seller-messages.js +4 -30
- package/dist/commands/seller-messages.js.map +1 -1
- package/dist/session/cart-locators.js +123 -0
- package/dist/session/cart-locators.js.map +1 -0
- package/dist/session/checkout-locators.js +13 -0
- package/dist/session/checkout-locators.js.map +1 -0
- package/dist/session/im-locators.js +103 -0
- package/dist/session/im-locators.js.map +1 -0
- package/dist/session/image-search-locators.js +30 -0
- package/dist/session/image-search-locators.js.map +1 -0
- package/dist/session/locator.js +86 -0
- package/dist/session/locator.js.map +1 -0
- package/dist/session/offer-locators.js +42 -0
- package/dist/session/offer-locators.js.map +1 -0
- package/dist/session/search-locators.js +16 -0
- package/dist/session/search-locators.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { CliError } from '../io/errors.js';
|
|
2
|
+
import { clickStable } from './locator.js';
|
|
3
|
+
export async function waitForCartItems(page, timeoutMs = 15000) {
|
|
4
|
+
try {
|
|
5
|
+
await page.waitForSelector('input[type="checkbox"].next-checkbox-input', {
|
|
6
|
+
timeout: timeoutMs,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
throw new CliError(11, 'CART_NOT_LOADED', 'Cart page did not load.');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function uncheckAllCartRows(page) {
|
|
14
|
+
await page.evaluate(() => {
|
|
15
|
+
const wrappers = Array.from(document.querySelectorAll('.next-checkbox-wrapper'));
|
|
16
|
+
for (const wrapper of wrappers) {
|
|
17
|
+
const aria = wrapper.querySelector('[aria-checked]');
|
|
18
|
+
if (aria?.getAttribute('aria-checked') === 'true') {
|
|
19
|
+
wrapper.click();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export async function clickCartRowCheckbox(page, item) {
|
|
25
|
+
const result = await page.evaluate(({ titleHint, skuHint }) => {
|
|
26
|
+
const probe = skuHint && skuHint.length >= 3 ? skuHint : titleHint;
|
|
27
|
+
const all = Array.from(document.querySelectorAll('*'));
|
|
28
|
+
const candidates = all.filter((el) => el.children.length === 0 &&
|
|
29
|
+
el.textContent !== null &&
|
|
30
|
+
el.textContent.includes(probe));
|
|
31
|
+
for (const candidate of candidates) {
|
|
32
|
+
let row = candidate;
|
|
33
|
+
for (let depth = 0; depth < 10 && row; depth++) {
|
|
34
|
+
row = row.parentElement;
|
|
35
|
+
if (!row)
|
|
36
|
+
break;
|
|
37
|
+
const text = row.textContent ?? '';
|
|
38
|
+
if (!text.includes(titleHint))
|
|
39
|
+
continue;
|
|
40
|
+
const checkbox = row.querySelector('.next-checkbox-wrapper');
|
|
41
|
+
if (checkbox) {
|
|
42
|
+
const aria = checkbox.querySelector('[aria-checked]');
|
|
43
|
+
const checked = aria?.getAttribute('aria-checked') === 'true';
|
|
44
|
+
if (!checked)
|
|
45
|
+
checkbox.click();
|
|
46
|
+
return { ok: true, checked };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { ok: false, reason: 'row-not-found' };
|
|
51
|
+
}, {
|
|
52
|
+
titleHint: item.productTitle.slice(0, 12),
|
|
53
|
+
skuHint: item.skuTitle?.trim() ?? null,
|
|
54
|
+
});
|
|
55
|
+
if (!result.ok) {
|
|
56
|
+
throw new CliError(14, 'STABLE_LOCATOR_NOT_FOUND', `Could not locate cart row checkbox for cartId ${item.cartId}.`, {
|
|
57
|
+
category: 'locator',
|
|
58
|
+
locatorDescription: 'cart row checkbox',
|
|
59
|
+
locatorStrategies: [
|
|
60
|
+
'skuTitle text within nearest row containing productTitle',
|
|
61
|
+
'productTitle text within nearest row containing checkbox',
|
|
62
|
+
],
|
|
63
|
+
cartId: item.cartId,
|
|
64
|
+
productTitle: item.productTitle,
|
|
65
|
+
skuTitle: item.skuTitle,
|
|
66
|
+
currentUrl: page.url(),
|
|
67
|
+
retryable: true,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export async function clickCartDeleteButton(page) {
|
|
72
|
+
await clickStable(page, [
|
|
73
|
+
{ kind: 'role', role: 'button', name: /^删除$/ },
|
|
74
|
+
{ kind: 'css', selector: 'button:has-text("删除"):not([disabled])' },
|
|
75
|
+
{ kind: 'text', text: /^删除$/ },
|
|
76
|
+
], {
|
|
77
|
+
description: 'cart delete button',
|
|
78
|
+
timeoutMs: 5000,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export async function clickConfirmDialogButton(page) {
|
|
82
|
+
await clickStable(page, [
|
|
83
|
+
{ kind: 'role', role: 'button', name: /确认|确定|确认加入|加入采购车/ },
|
|
84
|
+
{ kind: 'css', selector: '[role="dialog"] button:has-text("确认"):visible' },
|
|
85
|
+
{ kind: 'css', selector: '[role="dialog"] button:has-text("确定"):visible' },
|
|
86
|
+
{ kind: 'css', selector: 'div[class*="dialog"] button.next-btn-primary:visible' },
|
|
87
|
+
], {
|
|
88
|
+
description: 'confirmation dialog primary button',
|
|
89
|
+
timeoutMs: 5000,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
export async function clickCartCheckoutButton(page) {
|
|
93
|
+
await clickStable(page, [
|
|
94
|
+
{ kind: 'role', role: 'button', name: /^结算$/ },
|
|
95
|
+
{ kind: 'css', selector: 'button:has-text("结算"):not([disabled])' },
|
|
96
|
+
{ kind: 'text', text: /^结算$/ },
|
|
97
|
+
], {
|
|
98
|
+
description: 'cart checkout button',
|
|
99
|
+
timeoutMs: 5000,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
export async function waitForAnyCartRowChecked(page) {
|
|
103
|
+
const checked = await page
|
|
104
|
+
.waitForFunction(() => {
|
|
105
|
+
const wrappers = Array.from(document.querySelectorAll('.next-checkbox-wrapper'));
|
|
106
|
+
return wrappers.some((wrapper) => {
|
|
107
|
+
const aria = wrapper.querySelector('[aria-checked]');
|
|
108
|
+
return aria?.getAttribute('aria-checked') === 'true';
|
|
109
|
+
});
|
|
110
|
+
}, { timeout: 8000 })
|
|
111
|
+
.then(() => true)
|
|
112
|
+
.catch(() => false);
|
|
113
|
+
if (!checked) {
|
|
114
|
+
throw new CliError(14, 'STABLE_LOCATOR_NOT_FOUND', 'Target cart item did not register as selected.', {
|
|
115
|
+
category: 'locator',
|
|
116
|
+
locatorDescription: 'checked cart row',
|
|
117
|
+
locatorStrategies: ['any .next-checkbox-wrapper [aria-checked=true]'],
|
|
118
|
+
currentUrl: page.url(),
|
|
119
|
+
retryable: true,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=cart-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart-locators.js","sourceRoot":"","sources":["../../src/session/cart-locators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { clickStable } from './locator.js';
|
|
2
|
+
export async function clickSubmitOrderButton(page) {
|
|
3
|
+
await clickStable(page, [
|
|
4
|
+
{ kind: 'role', role: 'button', name: /^提交订单$/ },
|
|
5
|
+
{ kind: 'text', text: /^提交订单$/ },
|
|
6
|
+
{ kind: 'css', selector: 'q-button:has-text("提交订单")' },
|
|
7
|
+
{ kind: 'css', selector: 'button:has-text("提交订单"):not([disabled])' },
|
|
8
|
+
], {
|
|
9
|
+
description: 'checkout submit order button',
|
|
10
|
+
timeoutMs: 15000,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=checkout-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout-locators.js","sourceRoot":"","sources":["../../src/session/checkout-locators.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAU;IACrD,MAAM,WAAW,CACf,IAAI,EACJ;QACE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;QAChD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;QAChC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,2BAA2B,EAAE;QACtD,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,yCAAyC,EAAE;KACrE,EACD;QACE,WAAW,EAAE,8BAA8B;QAC3C,SAAS,EAAE,KAAK;KACjB,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { CliError } from '../io/errors.js';
|
|
2
|
+
export function imFrame(page) {
|
|
3
|
+
return page.frameLocator('iframe[src*="def_cbu_web_im_core"]');
|
|
4
|
+
}
|
|
5
|
+
export async function findImInput(page) {
|
|
6
|
+
const input = imFrame(page).locator('pre.edit[contenteditable="true"]').first();
|
|
7
|
+
try {
|
|
8
|
+
await input.waitFor({ state: 'visible', timeout: 20000 });
|
|
9
|
+
return input;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new CliError(22, 'STABLE_LOCATOR_NOT_FOUND', 'Could not locate 旺旺 IM chat input.', {
|
|
13
|
+
category: 'locator',
|
|
14
|
+
locatorDescription: 'wangwang chat input',
|
|
15
|
+
locatorStrategies: ['iframe def_cbu_web_im_core >> pre.edit[contenteditable=true]'],
|
|
16
|
+
currentUrl: page.url(),
|
|
17
|
+
retryable: true,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function clickConversationByName(page, names) {
|
|
22
|
+
const frame = imFrame(page);
|
|
23
|
+
for (const name of names) {
|
|
24
|
+
if (!name)
|
|
25
|
+
continue;
|
|
26
|
+
const item = frame.locator(`text=${name}`).first();
|
|
27
|
+
const visible = await item.isVisible({ timeout: 2000 }).catch(() => false);
|
|
28
|
+
if (!visible)
|
|
29
|
+
continue;
|
|
30
|
+
try {
|
|
31
|
+
await item.click({ force: true, timeout: 5000 });
|
|
32
|
+
return name;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
throw new CliError(14, 'STABLE_LOCATOR_BLOCKED', `Located 旺旺 conversation "${name}", but it was not clickable: ${e.message}`, {
|
|
36
|
+
category: 'locator',
|
|
37
|
+
locatorDescription: 'wangwang sidebar conversation',
|
|
38
|
+
locatorStrategies: names.map((n) => `iframe text=${n}`),
|
|
39
|
+
currentUrl: page.url(),
|
|
40
|
+
retryable: true,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
export async function waitForConversationActivated(page, matchedName, args) {
|
|
47
|
+
const activated = await page
|
|
48
|
+
.waitForFunction(() => {
|
|
49
|
+
const iframe = document.querySelector('iframe[src*="def_cbu_web_im_core"]');
|
|
50
|
+
const body = iframe?.contentDocument?.body?.innerText ?? '';
|
|
51
|
+
return !/您尚未选择联系人/.test(body) && body.length > 50;
|
|
52
|
+
}, { timeout: 25000 })
|
|
53
|
+
.then(() => true)
|
|
54
|
+
.catch(() => false);
|
|
55
|
+
if (!activated) {
|
|
56
|
+
throw new CliError(26, 'CONVERSATION_NOT_SELECTED', `Conversation panel did not activate for ${matchedName}. ` +
|
|
57
|
+
(args.orderId
|
|
58
|
+
? `OrderId ${args.orderId} was passed but conversation never opened.`
|
|
59
|
+
: 'Sidebar click did not switch to conversation.'), {
|
|
60
|
+
category: 'locator',
|
|
61
|
+
locatorDescription: 'wangwang active conversation panel',
|
|
62
|
+
locatorStrategies: ['iframe body text does not contain 您尚未选择联系人'],
|
|
63
|
+
currentUrl: page.url(),
|
|
64
|
+
retryable: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function clickImSendButton(page) {
|
|
69
|
+
const button = imFrame(page).locator('button.send-btn:has-text("发送")').first();
|
|
70
|
+
try {
|
|
71
|
+
await button.click({ force: true, timeout: 5000 });
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
throw new CliError(14, 'STABLE_LOCATOR_BLOCKED', `Located 旺旺 send button, but it was not clickable: ${e.message}`, {
|
|
75
|
+
category: 'locator',
|
|
76
|
+
locatorDescription: 'wangwang send button',
|
|
77
|
+
locatorStrategies: ['iframe button.send-btn:has-text("发送")'],
|
|
78
|
+
currentUrl: page.url(),
|
|
79
|
+
retryable: true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export async function waitForMessageSent(page, message) {
|
|
84
|
+
const sent = await page
|
|
85
|
+
.waitForFunction((msg) => {
|
|
86
|
+
const iframe = document.querySelector('iframe[src*="def_cbu_web_im_core"]');
|
|
87
|
+
const doc = iframe?.contentDocument;
|
|
88
|
+
if (!doc)
|
|
89
|
+
return false;
|
|
90
|
+
const edit = doc.querySelector('pre.edit[contenteditable="true"]');
|
|
91
|
+
const editText = (edit?.innerText ?? '').replace(/\s+/g, '');
|
|
92
|
+
if (editText.length === 0)
|
|
93
|
+
return true;
|
|
94
|
+
const body = doc.body?.innerText ?? '';
|
|
95
|
+
return body.includes(msg);
|
|
96
|
+
}, message, { timeout: 10000 })
|
|
97
|
+
.then(() => true)
|
|
98
|
+
.catch(() => false);
|
|
99
|
+
if (!sent) {
|
|
100
|
+
throw new CliError(24, 'SEND_UNCONFIRMED', 'Send clicked but neither input cleared nor message appeared in scrollback.');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=im-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"im-locators.js","sourceRoot":"","sources":["../../src/session/im-locators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { clickStable, findVisible } from './locator.js';
|
|
2
|
+
export async function clickImageUploadButton(page) {
|
|
3
|
+
await clickStable(page, [
|
|
4
|
+
{ kind: 'role', role: 'button', name: /上传图片|图片上传|选择图片/ },
|
|
5
|
+
{ kind: 'css', selector: '.image-upload-button-container' },
|
|
6
|
+
{ kind: 'css', selector: '[class*="image-upload"]' },
|
|
7
|
+
], {
|
|
8
|
+
description: 'image search upload button',
|
|
9
|
+
timeoutMs: 8000,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export async function clickImageSearchButton(page) {
|
|
13
|
+
await findVisible(page, [
|
|
14
|
+
{ kind: 'role', role: 'button', name: /^搜索图片$/ },
|
|
15
|
+
{ kind: 'text', text: /^搜索图片$/ },
|
|
16
|
+
{ kind: 'css', selector: 'button:has-text("搜索图片")' },
|
|
17
|
+
], {
|
|
18
|
+
description: 'image search submit button',
|
|
19
|
+
timeoutMs: 20000,
|
|
20
|
+
});
|
|
21
|
+
await clickStable(page, [
|
|
22
|
+
{ kind: 'role', role: 'button', name: /^搜索图片$/ },
|
|
23
|
+
{ kind: 'css', selector: 'button:has-text("搜索图片")' },
|
|
24
|
+
{ kind: 'text', text: /^搜索图片$/ },
|
|
25
|
+
], {
|
|
26
|
+
description: 'image search submit button',
|
|
27
|
+
timeoutMs: 5000,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=image-search-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-search-locators.js","sourceRoot":"","sources":["../../src/session/image-search-locators.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAU;IACrD,MAAM,WAAW,CACf,IAAI,EACJ;QACE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,gBAAgB,EAAE;QACxD,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,gCAAgC,EAAE;QAC3D,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,yBAAyB,EAAE;KACrD,EACD;QACE,WAAW,EAAE,4BAA4B;QACzC,SAAS,EAAE,IAAI;KAChB,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAU;IACrD,MAAM,WAAW,CACf,IAAI,EACJ;QACE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;QAChD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;QAChC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,yBAAyB,EAAE;KACrD,EACD;QACE,WAAW,EAAE,4BAA4B;QACzC,SAAS,EAAE,KAAK;KACjB,CACF,CAAC;IAEF,MAAM,WAAW,CACf,IAAI,EACJ;QACE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;QAChD,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,yBAAyB,EAAE;QACpD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;KACjC,EACD;QACE,WAAW,EAAE,4BAA4B;QACzC,SAAS,EAAE,IAAI;KAChB,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { CliError } from '../io/errors.js';
|
|
2
|
+
export function locatorCandidateToDebugString(candidate) {
|
|
3
|
+
switch (candidate.kind) {
|
|
4
|
+
case 'role':
|
|
5
|
+
return `role=${candidate.role} name=${String(candidate.name)}`;
|
|
6
|
+
case 'text':
|
|
7
|
+
return `text=${String(candidate.text)}`;
|
|
8
|
+
case 'css':
|
|
9
|
+
return `css=${candidate.selector}`;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function locatorFor(page, candidate) {
|
|
13
|
+
switch (candidate.kind) {
|
|
14
|
+
case 'role':
|
|
15
|
+
return page.getByRole(candidate.role, { name: candidate.name }).first();
|
|
16
|
+
case 'text':
|
|
17
|
+
return page.getByText(candidate.text).first();
|
|
18
|
+
case 'css':
|
|
19
|
+
return page.locator(candidate.selector).first();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function isLocatorUsable(locator, opts) {
|
|
23
|
+
const requireVisible = opts.requireVisible ?? true;
|
|
24
|
+
const requireEnabled = opts.requireEnabled ?? true;
|
|
25
|
+
if (requireVisible && !(await locator.isVisible().catch(() => false))) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (requireEnabled && !(await locator.isEnabled().catch(() => false))) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
export async function findVisible(page, candidates, opts) {
|
|
34
|
+
return findUsable(page, candidates, { ...opts, requireVisible: true });
|
|
35
|
+
}
|
|
36
|
+
export async function findClickable(page, candidates, opts) {
|
|
37
|
+
return findUsable(page, candidates, {
|
|
38
|
+
...opts,
|
|
39
|
+
requireVisible: true,
|
|
40
|
+
requireEnabled: true,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function findUsable(page, candidates, opts) {
|
|
44
|
+
const timeoutMs = opts.timeoutMs ?? 5000;
|
|
45
|
+
const deadline = Date.now() + timeoutMs;
|
|
46
|
+
const strategies = candidates.map(locatorCandidateToDebugString);
|
|
47
|
+
while (Date.now() <= deadline) {
|
|
48
|
+
for (const candidate of candidates) {
|
|
49
|
+
const locator = locatorFor(page, candidate);
|
|
50
|
+
if (await isLocatorUsable(locator, opts)) {
|
|
51
|
+
if (opts.scrollIntoView ?? true) {
|
|
52
|
+
await locator.scrollIntoViewIfNeeded({ timeout: 1000 }).catch(() => { });
|
|
53
|
+
}
|
|
54
|
+
return locator;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
58
|
+
}
|
|
59
|
+
throw new CliError(14, 'STABLE_LOCATOR_NOT_FOUND', `Could not locate ${opts.description}.`, {
|
|
60
|
+
category: 'locator',
|
|
61
|
+
locatorDescription: opts.description,
|
|
62
|
+
locatorStrategies: strategies,
|
|
63
|
+
currentUrl: page.url(),
|
|
64
|
+
retryable: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export async function clickStable(page, candidates, opts) {
|
|
68
|
+
const locator = await findClickable(page, candidates, opts);
|
|
69
|
+
try {
|
|
70
|
+
await locator.click({ timeout: opts.timeoutMs ?? 5000 });
|
|
71
|
+
return {
|
|
72
|
+
strategy: candidates.map(locatorCandidateToDebugString).join(' | '),
|
|
73
|
+
description: opts.description,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
throw new CliError(14, 'STABLE_LOCATOR_BLOCKED', `Located ${opts.description}, but it was not clickable: ${e.message}`, {
|
|
78
|
+
category: 'locator',
|
|
79
|
+
locatorDescription: opts.description,
|
|
80
|
+
locatorStrategies: candidates.map(locatorCandidateToDebugString),
|
|
81
|
+
currentUrl: page.url(),
|
|
82
|
+
retryable: true,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=locator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locator.js","sourceRoot":"","sources":["../../src/session/locator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CliError } from '../io/errors.js';
|
|
2
|
+
import { clickStable, findVisible } from './locator.js';
|
|
3
|
+
export async function fillFirstSkuQuantityInput(page, quantity) {
|
|
4
|
+
const input = await findVisible(page, [
|
|
5
|
+
{ kind: 'css', selector: 'input.ant-input-number-input' },
|
|
6
|
+
{ kind: 'css', selector: 'input[type="text"][role="spinbutton"]' },
|
|
7
|
+
{ kind: 'css', selector: 'input[class*="input-number"]' },
|
|
8
|
+
], {
|
|
9
|
+
description: 'offer SKU quantity input',
|
|
10
|
+
timeoutMs: 12000,
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
await input.click({ force: true, timeout: 3000 });
|
|
14
|
+
await input.fill(String(quantity));
|
|
15
|
+
await page.keyboard.press('Tab');
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
throw new CliError(14, 'STABLE_LOCATOR_BLOCKED', `Located offer SKU quantity input, but it could not be filled: ${e.message}`, {
|
|
19
|
+
category: 'locator',
|
|
20
|
+
locatorDescription: 'offer SKU quantity input',
|
|
21
|
+
locatorStrategies: [
|
|
22
|
+
'input.ant-input-number-input',
|
|
23
|
+
'input[type=text][role=spinbutton]',
|
|
24
|
+
'input[class*=input-number]',
|
|
25
|
+
],
|
|
26
|
+
currentUrl: page.url(),
|
|
27
|
+
retryable: true,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export async function clickAddCartButton(page) {
|
|
32
|
+
await clickStable(page, [
|
|
33
|
+
{ kind: 'role', role: 'button', name: /加采购车|加入采购车|加入进货单/ },
|
|
34
|
+
{ kind: 'css', selector: 'button:has-text("加采购车"):not([disabled])' },
|
|
35
|
+
{ kind: 'css', selector: 'button:has-text("加入采购车"):not([disabled])' },
|
|
36
|
+
{ kind: 'css', selector: 'button:has-text("加入进货单"):not([disabled])' },
|
|
37
|
+
], {
|
|
38
|
+
description: 'offer add-to-cart button',
|
|
39
|
+
timeoutMs: 15000,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=offer-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offer-locators.js","sourceRoot":"","sources":["../../src/session/offer-locators.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAAU,EACV,QAAgB;IAEhB,MAAM,KAAK,GAAG,MAAM,WAAW,CAC7B,IAAI,EACJ;QACE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,8BAA8B,EAAE;QACzD,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,uCAAuC,EAAE;QAClE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,8BAA8B,EAAE;KAC1D,EACD;QACE,WAAW,EAAE,0BAA0B;QACvC,SAAS,EAAE,KAAK;KACjB,CACF,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACnC,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,QAAQ,CAChB,EAAE,EACF,wBAAwB,EACxB,iEAAkE,CAAW,CAAC,OAAO,EAAE,EACvF;YACE,QAAQ,EAAE,SAAS;YACnB,kBAAkB,EAAE,0BAA0B;YAC9C,iBAAiB,EAAE;gBACjB,8BAA8B;gBAC9B,mCAAmC;gBACnC,4BAA4B;aAC7B;YACD,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;YACtB,SAAS,EAAE,IAAI;SAChB,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAU;IACjD,MAAM,WAAW,CACf,IAAI,EACJ;QACE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB,EAAE;QAC1D,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,yCAAyC,EAAE;QACpE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,0CAA0C,EAAE;QACrE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,0CAA0C,EAAE;KACtE,EACD;QACE,WAAW,EAAE,0BAA0B;QACvC,SAAS,EAAE,KAAK;KACjB,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { clickStable, findVisible } from './locator.js';
|
|
2
|
+
const NEXT_PAGE_SELECTOR = '.fui-arrow.fui-next:not(.fui-next-disabled)';
|
|
3
|
+
export async function clickSearchNextPage(page) {
|
|
4
|
+
const next = await findVisible(page, [{ kind: 'css', selector: NEXT_PAGE_SELECTOR }], {
|
|
5
|
+
description: 'search next page button',
|
|
6
|
+
timeoutMs: 1000,
|
|
7
|
+
}).catch(() => null);
|
|
8
|
+
if (!next)
|
|
9
|
+
return false;
|
|
10
|
+
await clickStable(page, [{ kind: 'css', selector: NEXT_PAGE_SELECTOR }], {
|
|
11
|
+
description: 'search next page button',
|
|
12
|
+
timeoutMs: 5000,
|
|
13
|
+
});
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=search-locators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-locators.js","sourceRoot":"","sources":["../../src/session/search-locators.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAExD,MAAM,kBAAkB,GAAG,6CAA6C,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAU;IAClD,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,IAAI,EACJ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC,EAC/C;QACE,WAAW,EAAE,yBAAyB;QACtC,SAAS,EAAE,IAAI;KAChB,CACF,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACpB,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAExB,MAAM,WAAW,CACf,IAAI,EACJ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC,EAC/C;QACE,WAAW,EAAE,yBAAyB;QACtC,SAAS,EAAE,IAAI;KAChB,CACF,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "1688-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "1688.com CLI for humans, Codex, and Claude Code. Sourcing (search / image-search / offer / inquire) and orders (list / detail / logistics / seller chat).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "nobodyjack",
|