重构 Kiro 注册页面状态收养

This commit is contained in:
QLHazyCoder
2026-05-20 20:42:29 +08:00
parent 065607bc04
commit 59b7d77b5d
5 changed files with 618 additions and 70 deletions
@@ -35,7 +35,136 @@ test('kiro register runner uses a shared 3-minute page-load timeout budget', ()
test('kiro register consent step treats Kiro Web signed-in page as completion', () => {
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
assert.match(source, /targetStates: \['authorization_page', 'kiro_web_signed_in'\]/);
assert.match(source, /landingResult\?\.state !== 'kiro_web_signed_in'/);
assert.match(source, /readKiroRegisterPageState\(tabId, \{/);
assert.match(source, /\['authorization_page', 'success_page', 'kiro_web_signed_in'\]\.includes\(landingResult\?\.state\)/);
assert.match(source, /landingResult\?\.state === 'authorization_page'/);
assert.doesNotMatch(source, /landingResult\?\.state !== 'success_page'/);
});
test('kiro register runner uses registration-only page states instead of shared OpenAI names', () => {
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
assert.match(source, /KIRO_REGISTER_PAGE_STATES/);
assert.match(source, /'register_otp_page'/);
assert.match(source, /'create_password_page'/);
assert.match(source, /'login_password_page'/);
assert.match(source, /'login_otp_page'/);
assert.doesNotMatch(source, /targetStates: \['otp_page'\]/);
assert.doesNotMatch(source, /targetStates: \['password_page'\]/);
assert.doesNotMatch(source, /fromStates: \['password_page'\]/);
});
test('kiro register runner fails existing-account login branches during registration', () => {
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
assert.match(source, /KIRO_REGISTER_EXISTING_ACCOUNT_STATES/);
assert.match(source, /assertKiroRegistrationOnlyState\(landingResult, currentState, 2, resolvedEmail\)/);
assert.match(source, /邮箱.*已进入 AWS Builder ID 登录页/);
assert.match(source, /Kiro 注册流程只处理新账号注册/);
});
test('kiro submit-email stops immediately when AWS routes the email to login', async () => {
const api = loadRegisterRunnerApi();
const currentState = {
kiroRuntime: {
session: {
registerTabId: 101,
},
register: {
loginUrl: 'https://app.kiro.dev/signin',
},
},
};
const sentMessages = [];
const statePatches = [];
let completed = false;
const runner = api.createKiroRegisterRunner({
addLog: async () => {},
chrome: {
tabs: {
update: async () => {},
},
},
completeNodeFromBackground: async () => {
completed = true;
},
getState: async () => currentState,
getTabId: async () => 101,
isTabAlive: async () => true,
resolveSignupEmailForFlow: async () => 'existing-user@duck.com',
sendToContentScriptResilient: async (_sourceId, message) => {
sentMessages.push(message);
if (message.type === 'ENSURE_KIRO_PAGE_STATE') {
return { state: 'email_entry', url: 'https://us-east-1.signin.aws/platform/d/signup' };
}
if (message.type === 'EXECUTE_NODE') {
return { submitted: true, state: 'email_submitted' };
}
if (message.type === 'ENSURE_KIRO_STATE_CHANGE') {
return {
state: 'login_password_page',
url: 'https://us-east-1.signin.aws/platform/d/login',
email: 'existing-user@duck.com',
};
}
return {};
},
setState: async (patch) => {
statePatches.push(patch);
},
});
await assert.rejects(
() => runner.executeKiroSubmitEmail({ nodeId: 'kiro-submit-email', ...currentState }),
/existing-user@duck\.com.*已进入 AWS Builder ID 登录页/
);
assert.equal(completed, false);
assert.equal(sentMessages.some((message) => message.type === 'EXECUTE_NODE'), true);
assert.equal(statePatches.some((patch) => /已进入 AWS Builder ID 登录页/.test(patch.kiroRuntime?.session?.lastError || '')), true);
});
test('kiro submit-email can adopt an already-open registration OTP page without allocating a new mailbox', async () => {
const api = loadRegisterRunnerApi();
const currentState = {
kiroRuntime: {
session: {
registerTabId: 102,
},
register: {
loginUrl: 'https://app.kiro.dev/signin',
},
},
};
const sentMessages = [];
let completedPayload = null;
const runner = api.createKiroRegisterRunner({
addLog: async () => {},
chrome: {
tabs: {
update: async () => {},
},
},
completeNodeFromBackground: async (_nodeId, payload) => {
completedPayload = payload;
},
getState: async () => currentState,
getTabId: async () => 102,
isTabAlive: async () => true,
sendToContentScriptResilient: async (_sourceId, message) => {
sentMessages.push(message);
assert.equal(message.type, 'ENSURE_KIRO_PAGE_STATE');
return {
state: 'register_otp_page',
url: 'https://us-east-1.signin.aws/platform/d/signup',
email: 'manual-user@duck.com',
};
},
setState: async () => {},
});
await runner.executeKiroSubmitEmail({ nodeId: 'kiro-submit-email', ...currentState });
assert.equal(completedPayload?.kiroRuntime?.register?.email, 'manual-user@duck.com');
assert.equal(completedPayload?.kiroRuntime?.register?.status, 'waiting_otp');
assert.equal(completedPayload?.kiroRuntime?.register?.verificationRequestedAt, 0);
assert.equal(sentMessages.some((message) => message.type === 'EXECUTE_NODE'), false);
});
+2 -2
View File
@@ -74,7 +74,7 @@ test('kiro state session patch accepts canonical nested runtime updates', () =>
kiroRuntime: {
session: {
currentStage: 'register',
pageState: 'otp_page',
pageState: 'register_otp_page',
pageUrl: 'https://signin.aws/register',
},
register: {
@@ -92,7 +92,7 @@ test('kiro state session patch accepts canonical nested runtime updates', () =>
});
assert.equal(patch.kiroRuntime.session.currentStage, 'register');
assert.equal(patch.kiroRuntime.session.pageState, 'otp_page');
assert.equal(patch.kiroRuntime.session.pageState, 'register_otp_page');
assert.equal(patch.kiroRuntime.session.pageUrl, 'https://signin.aws/register');
assert.equal(patch.kiroRuntime.register.email, 'aws-user@example.com');
assert.equal(patch.kiroRuntime.register.fullName, 'Ada Lovelace');
+71 -1
View File
@@ -87,6 +87,7 @@ function createDomHarness({
}
const context = {
console: { log() {}, warn() {}, error() {}, info() {} },
URL,
location: { href, hostname },
document: {
title,
@@ -109,6 +110,10 @@ function createDomHarness({
if (String(selector).startsWith('label[for=')) {
return [];
}
const testIdMatch = String(selector).match(/\[data-testid="([^"]+)"\]/);
if (testIdMatch) {
return [...inputs, ...buttons].filter((element) => element.getAttribute?.('data-testid') === testIdMatch[1]);
}
if (String(selector).trim().startsWith('input')) {
return inputs;
}
@@ -234,7 +239,7 @@ test('kiro register content fills primary and confirm password fields separately
harness.simulateClick = (element) => clicks.push(element);
const detected = harness.detectKiroRegisterPageState();
assert.equal(detected.state, 'password_page');
assert.equal(detected.state, 'create_password_page');
assert.equal(detected.passwordInput, passwordInput);
assert.equal(detected.confirmPasswordInput, confirmPasswordInput);
@@ -245,3 +250,68 @@ test('kiro register content fills primary and confirm password fields separately
assert.equal(confirmPasswordInput.value, 'mdy8U9_rzqhw6D');
assert.deepEqual(clicks, [continueButton]);
});
test('kiro register content classifies AWS login password as an existing-account branch', () => {
const passwordInput = createInputElement({
id: 'formField15-1779237828927-4809',
type: 'text',
placeholder: 'Enter password',
label: '\u5bc6\u7801',
});
const continueButton = createButtonElement({ text: '\u7ee7\u7eed' });
const harness = createDomHarness({
href: 'https://us-east-1.signin.aws/platform/d-9067642ac7/login?workflowStateHandle=abc',
hostname: 'us-east-1.signin.aws',
title: 'Amazon Web Services',
bodyText: 'Sign in with your AWS Builder ID Email much-glance-avert@duck.com Change',
inputs: [passwordInput],
buttons: [continueButton],
});
const detected = harness.detectKiroRegisterPageState();
assert.equal(detected.state, 'login_password_page');
assert.equal(detected.email, 'much-glance-avert@duck.com');
assert.equal(detected.passwordInput, passwordInput);
});
test('kiro register content classifies signup verification separately from login verification', () => {
const registerOtpInput = createInputElement({
id: 'formField38-1779237828927-4809',
type: 'text',
placeholder: '6-digit',
label: '\u9a8c\u8bc1\u7801',
});
const loginOtpInput = createInputElement({
id: 'formField38-1779237828927-4810',
type: 'text',
placeholder: '6-digit',
label: '\u9a8c\u8bc1\u7801',
});
const registerHarness = createDomHarness({
href: 'https://us-east-1.signin.aws/platform/d-9067642ac7/signup?state=abc',
hostname: 'us-east-1.signin.aws',
title: 'Amazon Web Services',
bodyText: 'Verify your identity Email new-user@duck.com',
inputs: [registerOtpInput],
buttons: [createButtonElement()],
});
const loginHarness = createDomHarness({
href: 'https://us-east-1.signin.aws/platform/d-9067642ac7/login?workflowStateHandle=abc',
hostname: 'us-east-1.signin.aws',
title: 'Amazon Web Services',
bodyText: 'Verify your identity Email existing-user@duck.com',
inputs: [loginOtpInput],
buttons: [createButtonElement()],
});
const registerDetected = registerHarness.detectKiroRegisterPageState();
const loginDetected = loginHarness.detectKiroRegisterPageState();
assert.equal(registerDetected.state, 'register_otp_page');
assert.equal(registerDetected.email, 'new-user@duck.com');
assert.equal(loginDetected.state, 'login_otp_page');
assert.equal(loginDetected.email, 'existing-user@duck.com');
});