Files
FlowPilot/tests/background-runtime-state-module.test.js
T

174 lines
5.6 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
function loadRuntimeStateApi() {
const source = fs.readFileSync('background/runtime-state.js', 'utf8');
const globalScope = {};
return new Function('self', `${source}; return self.MultiPageBackgroundRuntimeState;`)(globalScope);
}
test('background imports runtime-state module and wires state view helpers', () => {
const source = fs.readFileSync('background.js', 'utf8');
assert.match(source, /background\/runtime-state\.js/);
assert.match(source, /createRuntimeStateHelpers/);
assert.match(source, /buildStateViewWithRuntimeState/);
assert.match(source, /buildStatePatchWithRuntimeState/);
assert.match(source, /runtimeState:/);
});
test('runtime-state module exposes a factory', () => {
const api = loadRuntimeStateApi();
assert.equal(typeof api?.createRuntimeStateHelpers, 'function');
});
test('runtime-state view preserves canonical flow metadata from node state', () => {
const api = loadRuntimeStateApi();
const helpers = api.createRuntimeStateHelpers({
DEFAULT_ACTIVE_FLOW_ID: 'openai',
defaultNodeStatuses: {
'open-chatgpt': 'pending',
'submit-signup-email': 'pending',
'oauth-login': 'pending',
},
});
const view = helpers.buildStateView({
currentNodeId: 'submit-signup-email',
nodeStatuses: {
'open-chatgpt': 'completed',
'submit-signup-email': 'running',
},
oauthUrl: 'https://auth.example.com/start',
plusCheckoutTabId: 88,
currentPhoneActivation: {
activationId: 'active-1',
phoneNumber: '+447700900123',
},
tabRegistry: {
'signup-page': { tabId: 12 },
},
sourceLastUrls: {
'signup-page': 'https://auth.example.com/start',
},
flowStartTime: 12345,
});
assert.equal(view.activeFlowId, 'openai');
assert.equal(view.currentNodeId, 'submit-signup-email');
assert.equal(Object.prototype.hasOwnProperty.call(view, 'legacyStepCompat'), false);
assert.equal(Object.prototype.hasOwnProperty.call(view, 'currentStep'), false);
assert.equal(Object.prototype.hasOwnProperty.call(view, 'stepStatuses'), false);
assert.deepStrictEqual(view.nodeStatuses, {
'open-chatgpt': 'completed',
'submit-signup-email': 'running',
'oauth-login': 'pending',
});
assert.equal(view.runtimeState.flowState.openai.auth.oauthUrl, 'https://auth.example.com/start');
assert.equal(view.runtimeState.flowState.openai.plus.plusCheckoutTabId, 88);
assert.deepStrictEqual(view.runtimeState.flowState.openai.phoneVerification.currentPhoneActivation, {
activationId: 'active-1',
phoneNumber: '+447700900123',
});
assert.deepStrictEqual(view.sharedState, {
tabRegistry: {
'signup-page': { tabId: 12 },
},
sourceLastUrls: {
'signup-page': 'https://auth.example.com/start',
},
flowStartTime: 12345,
});
});
test('runtime-state patch accepts nested flow and node updates without legacy step state', () => {
const api = loadRuntimeStateApi();
const helpers = api.createRuntimeStateHelpers({
DEFAULT_ACTIVE_FLOW_ID: 'openai',
defaultNodeStatuses: {
'open-chatgpt': 'pending',
'submit-signup-email': 'pending',
'oauth-login': 'pending',
},
});
const patch = helpers.buildSessionStatePatch({
currentNodeId: 'open-chatgpt',
nodeStatuses: {
'open-chatgpt': 'running',
'submit-signup-email': 'pending',
'oauth-login': 'pending',
},
oauthUrl: 'https://old.example.com/start',
}, {
runtimeState: {
activeRunId: 'run-001',
currentNodeId: 'oauth-login',
nodeStatuses: {
'open-chatgpt': 'completed',
'oauth-login': 'running',
},
flowState: {
openai: {
auth: {
oauthUrl: 'https://new.example.com/start',
},
plus: {
plusCheckoutTabId: 99,
},
},
},
},
});
assert.equal(patch.activeFlowId, 'openai');
assert.equal(patch.activeRunId, 'run-001');
assert.equal(patch.currentNodeId, 'oauth-login');
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'oauthUrl'), false);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'plusCheckoutTabId'), false);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'currentStep'), false);
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'stepStatuses'), false);
assert.deepStrictEqual(patch.nodeStatuses, {
'open-chatgpt': 'completed',
'submit-signup-email': 'pending',
'oauth-login': 'running',
});
assert.equal(patch.runtimeState.flowState.openai.auth.oauthUrl, 'https://new.example.com/start');
assert.equal(patch.runtimeState.flowState.openai.plus.plusCheckoutTabId, 99);
const view = helpers.buildStateView(patch);
assert.equal(view.oauthUrl, 'https://new.example.com/start');
assert.equal(view.plusCheckoutTabId, 99);
});
test('runtime-state patch prefers explicit activeFlowId over stale legacy flowId', () => {
const api = loadRuntimeStateApi();
const helpers = api.createRuntimeStateHelpers({
DEFAULT_ACTIVE_FLOW_ID: 'openai',
defaultNodeStatuses: {
'open-chatgpt': 'pending',
'kiro-open-register-page': 'pending',
},
});
const patch = helpers.buildSessionStatePatch({
flowId: 'openai',
activeFlowId: 'openai',
nodeStatuses: {
'open-chatgpt': 'completed',
},
}, {
activeFlowId: 'kiro',
nodeStatuses: {
'kiro-open-register-page': 'running',
},
});
assert.equal(patch.activeFlowId, 'kiro');
assert.equal(patch.flowId, 'kiro');
assert.deepStrictEqual(patch.nodeStatuses, {
'open-chatgpt': 'pending',
'kiro-open-register-page': 'running',
});
});