Bug Report
Title: getDynamicEmail always returns global email when executionId is provided, silently ignoring run-scoped email
Description
When executionId is passed to runSteps, getDynamicEmail() always returns the global dynamic email — even for step sets that never use {{global.dynamicEmail}} or any {{global.*}} placeholder.
This means {{email.extract(...)}} resolves against the wrong email address in any independent runSteps call that shares an executionId but expects its own isolated run-scoped email.
The bug is self-acknowledged in the source:
// src/index.ts
// ~~~ This logic needs to be fixed as global email will always be present if executionId is provided ~~~
const dynamicEmail = getDynamicEmail(localValues, globalValues);
Root Cause
getDynamicEmail in src/data-cache.ts:
export function getDynamicEmail(
localValues: LocalPlaceholders,
globalValues?: GlobalPlaceholders,
): string {
return globalValues?.["{{global.dynamicEmail}}"] || localValues["{{run.dynamicEmail}}"];
}
globalValues["{{global.dynamicEmail}}"] is always truthy when executionId is set because generateGlobalValues() unconditionally generates one:
// src/data-cache.ts
"{{global.dynamicEmail}}":
existingValues?.["{{global.dynamicEmail}}"] ??
(emailDomain ? `e2e-tester-${uuidv4()}@${emailDomain}` : ""),
So the || localValues["{{run.dynamicEmail}}"] fallback is never reached when an email domain is configured and executionId is present.
Steps to Reproduce
-
Configure an email provider with a domain:
configure({
email: {
domain: "yourdomain.com",
extractContent: async ({ email, prompt }) => { /* ... */ },
},
});
-
Run two independent runSteps calls with the same executionId but steps that only use {{run.dynamicEmail}}:
await runSteps({ page, executionId: "exec-1", steps: [
{ action: "fill", description: "Email field", data: { value: "{{run.dynamicEmail}}" } },
{ action: "fill", description: "OTP", data: { value: "{{email.extract(get the OTP)}}" } },
]});
-
Observe: {{email.extract(...)}} queries the global email (e2e-tester-<uuid>@yourdomain.com) instead of the run-scoped {{run.dynamicEmail}} address.
Expected Behavior
getDynamicEmail should return the global email only when the current step set actually references {{global.dynamicEmail}} or any {{global.*}} placeholder. For all other runSteps calls it should return the run-scoped {{run.dynamicEmail}} so each call is isolated.
Proposed Fix
processPlaceholders already computes hasGlobalPlaceholders (whether any step uses {{global.*}}). Expose it in the return value and thread it into getDynamicEmail as a preferGlobal flag:
src/data-cache.ts
export function getDynamicEmail(
localValues: LocalPlaceholders,
globalValues?: GlobalPlaceholders,
preferGlobal = false,
): string {
if (preferGlobal && globalValues?.["{{global.dynamicEmail}}"]) {
return globalValues["{{global.dynamicEmail}}"];
}
return localValues["{{run.dynamicEmail}}"];
}
src/index.ts
const { ..., hasGlobalPlaceholders } = await processPlaceholders(...);
// later in the loop:
const dynamicEmail = getDynamicEmail(localValues, globalValues, hasGlobalPlaceholders);
Fixes #54
Bug Report
Title:
getDynamicEmailalways returns global email whenexecutionIdis provided, silently ignoring run-scoped emailDescription
When
executionIdis passed torunSteps,getDynamicEmail()always returns the global dynamic email — even for step sets that never use{{global.dynamicEmail}}or any{{global.*}}placeholder.This means
{{email.extract(...)}}resolves against the wrong email address in any independentrunStepscall that shares anexecutionIdbut expects its own isolated run-scoped email.The bug is self-acknowledged in the source:
Root Cause
getDynamicEmailinsrc/data-cache.ts:globalValues["{{global.dynamicEmail}}"]is always truthy whenexecutionIdis set becausegenerateGlobalValues()unconditionally generates one:So the
|| localValues["{{run.dynamicEmail}}"]fallback is never reached when an email domain is configured andexecutionIdis present.Steps to Reproduce
Configure an email provider with a domain:
Run two independent
runStepscalls with the sameexecutionIdbut steps that only use{{run.dynamicEmail}}:Observe:
{{email.extract(...)}}queries the global email (e2e-tester-<uuid>@yourdomain.com) instead of the run-scoped{{run.dynamicEmail}}address.Expected Behavior
getDynamicEmailshould return the global email only when the current step set actually references{{global.dynamicEmail}}or any{{global.*}}placeholder. For all otherrunStepscalls it should return the run-scoped{{run.dynamicEmail}}so each call is isolated.Proposed Fix
processPlaceholdersalready computeshasGlobalPlaceholders(whether any step uses{{global.*}}). Expose it in the return value and thread it intogetDynamicEmailas apreferGlobalflag:src/data-cache.tssrc/index.tsFixes #54