fix: fix links in scenario service
This commit is contained in:
@@ -291,7 +291,7 @@ export function RunDetailPage() {
|
|||||||
items={[
|
items={[
|
||||||
{ label: t('scenarios.title'), icon: <ClipboardList size={14} />, onClick: () => navigate('/scenarios') },
|
{ label: t('scenarios.title'), icon: <ClipboardList size={14} />, onClick: () => navigate('/scenarios') },
|
||||||
{
|
{
|
||||||
label: scenario?.name ?? `#${id}`,
|
label: scenario?.name ?? `${id}`,
|
||||||
onClick: () => navigate(`/scenarios/${id}`),
|
onClick: () => navigate(`/scenarios/${id}`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -299,7 +299,7 @@ export function RunDetailPage() {
|
|||||||
icon: <Activity size={14} />,
|
icon: <Activity size={14} />,
|
||||||
onClick: () => navigate(`/scenarios/${id}/runs`),
|
onClick: () => navigate(`/scenarios/${id}/runs`),
|
||||||
},
|
},
|
||||||
{ label: `#${runId}` },
|
{ label: `${runId}` },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<AutoRefreshIndicator active={polling} pulseKey={pulseKey} error={!!error} onClick={manualRefresh} />
|
<AutoRefreshIndicator active={polling} pulseKey={pulseKey} error={!!error} onClick={manualRefresh} />
|
||||||
@@ -312,27 +312,28 @@ export function RunDetailPage() {
|
|||||||
<Card>
|
<Card>
|
||||||
<DescriptionList
|
<DescriptionList
|
||||||
layout="grid"
|
layout="grid"
|
||||||
items={[
|
items={(() => {
|
||||||
{ term: t('runs.field_id'), detail: <UuidBadge id={run.id} /> },
|
const items = [
|
||||||
{
|
{ term: t('runs.field_id'), detail: <UuidBadge id={run.id} /> },
|
||||||
term: t('runs.field_status'),
|
{
|
||||||
detail: (
|
term: t('runs.field_status'),
|
||||||
<Badge variant={RUN_STATUS_VARIANT[run.status]}>
|
detail: (
|
||||||
{RUN_STATUS_LABEL[run.status]}
|
<Badge variant={RUN_STATUS_VARIANT[run.status]}>
|
||||||
</Badge>
|
{RUN_STATUS_LABEL[run.status]}
|
||||||
),
|
</Badge>
|
||||||
},
|
),
|
||||||
{ term: t('runs.field_created'), detail: <Timestamp value={run.createdAt} /> },
|
},
|
||||||
{ term: t('runs.field_updated'), detail: <Timestamp value={run.updatedAt} /> },
|
{ term: t('runs.field_created'), detail: <Timestamp value={run.createdAt} /> },
|
||||||
...(run.environment ? [{
|
{ term: t('runs.field_updated'), detail: <Timestamp value={run.updatedAt} /> },
|
||||||
term: 'Environment',
|
];
|
||||||
detail: <span style={{ color: 'var(--color-link)', cursor: 'pointer' }}>{run.environment.name}</span>,
|
if (run.environment) {
|
||||||
}] : []),
|
items.push({ term: 'Environment', detail: <Link to={`/environments/${run.environment.id}`} style={{ color: 'var(--color-link)' }}>{run.environment.name}</Link> });
|
||||||
...(run.session ? [{
|
}
|
||||||
term: 'Session',
|
if (run.session) {
|
||||||
detail: <Link to={`/sessions/${run.session.id}`} style={{ color: 'var(--color-link)' }}>{run.session.sessionName}</Link>,
|
items.push({ term: 'Session', detail: <Link to={`/sessions/${run.session.id}`} style={{ color: 'var(--color-link)' }}>{run.session.sessionName}</Link> });
|
||||||
}] : []),
|
}
|
||||||
]}
|
return items;
|
||||||
|
})()}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@@ -559,7 +559,6 @@ export function ScenarioDetailPage() {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={saveSessionFlag}
|
checked={saveSessionFlag}
|
||||||
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
||||||
disabled
|
|
||||||
/>
|
/>
|
||||||
<span>Save session</span>
|
<span>Save session</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -222,7 +222,6 @@ export function ScenariosPage() {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={saveSessionFlag}
|
checked={saveSessionFlag}
|
||||||
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
onChange={(e) => setSaveSessionFlag(e.target.checked)}
|
||||||
disabled
|
|
||||||
/>
|
/>
|
||||||
<span>Save session</span>
|
<span>Save session</span>
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import {
|
|||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
} from "typeorm";
|
} from "typeorm";
|
||||||
import { ScenarioRunStepEntity } from "./scenario-run-step.entity";
|
|
||||||
import { ScenarioEntity } from "./scenario.entity";
|
|
||||||
import { EnvironmentEntity } from "../environment/environment.entity";
|
import { EnvironmentEntity } from "../environment/environment.entity";
|
||||||
import { SessionEntity } from "../session/session.entity";
|
import { SessionEntity } from "../session/session.entity";
|
||||||
|
import { ScenarioRunStepEntity } from "./scenario-run-step.entity";
|
||||||
|
import { ScenarioEntity } from "./scenario.entity";
|
||||||
|
|
||||||
export type RunStatus = "pending" | "in_progress" | "pass" | "fail";
|
export type RunStatus = "pending" | "in_progress" | "pass" | "fail";
|
||||||
|
|
||||||
@@ -23,8 +23,8 @@ export class ScenarioRunEntity {
|
|||||||
@Column("text")
|
@Column("text")
|
||||||
scenarioId: string;
|
scenarioId: string;
|
||||||
|
|
||||||
@Column("text", { default: "" })
|
@Column("text", { nullable: true, default: null })
|
||||||
environmentId: string;
|
environmentId: string | null;
|
||||||
|
|
||||||
@ManyToOne(() => ScenarioEntity, { onDelete: "CASCADE" })
|
@ManyToOne(() => ScenarioEntity, { onDelete: "CASCADE" })
|
||||||
@JoinColumn({ name: "scenarioId" })
|
@JoinColumn({ name: "scenarioId" })
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { chromium } from "playwright";
|
|||||||
import { Repository } from "typeorm";
|
import { Repository } from "typeorm";
|
||||||
import type { ScriptLogger } from "../code-executor/code-executor.service";
|
import type { ScriptLogger } from "../code-executor/code-executor.service";
|
||||||
import { CodeExecutorService } from "../code-executor/code-executor.service";
|
import { CodeExecutorService } from "../code-executor/code-executor.service";
|
||||||
|
import { ExecContextBuilder } from "../code-executor/exec-context.builder";
|
||||||
import { traceStorage } from "../common/trace-context";
|
import { traceStorage } from "../common/trace-context";
|
||||||
import { TraceLogger } from "../common/trace-logger";
|
import { TraceLogger } from "../common/trace-logger";
|
||||||
import { EnvironmentData, EnvironmentEntity } from "../environment/environment.entity";
|
import { EnvironmentData, EnvironmentEntity } from "../environment/environment.entity";
|
||||||
@@ -170,7 +171,9 @@ export class ScenarioSchedulerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handle = this.runBrowsers.get(runId);
|
const handle = this.runBrowsers.get(runId);
|
||||||
if (!handle) return;
|
if (!handle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const sessionName = `run-${runId}`;
|
const sessionName = `run-${runId}`;
|
||||||
try {
|
try {
|
||||||
@@ -184,7 +187,8 @@ export class ScenarioSchedulerService {
|
|||||||
cookies.find((c) => c.name === "token")?.value ??
|
cookies.find((c) => c.name === "token")?.value ??
|
||||||
"";
|
"";
|
||||||
|
|
||||||
await this.sessionService.upsert(sessionName, token, cookies, localStorage);
|
const session = await this.sessionService.upsert(sessionName, token, cookies, localStorage);
|
||||||
|
await this.runRepo.update(runId, { sessionId: session.id });
|
||||||
this.sessionContextService.register(
|
this.sessionContextService.register(
|
||||||
sessionName,
|
sessionName,
|
||||||
handle.browser,
|
handle.browser,
|
||||||
@@ -194,7 +198,7 @@ export class ScenarioSchedulerService {
|
|||||||
// Remove from runBrowsers so closeBrowserHandle won't close it
|
// Remove from runBrowsers so closeBrowserHandle won't close it
|
||||||
this.runBrowsers.delete(runId);
|
this.runBrowsers.delete(runId);
|
||||||
this.logger.log(
|
this.logger.log(
|
||||||
`Run #${runId}: browser preserved as session "${sessionName}"`,
|
`Run #${runId}: browser preserved as session "${sessionName}" (${session.id})`,
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
@@ -223,16 +227,17 @@ export class ScenarioSchedulerService {
|
|||||||
const creds = this.runCredentials.get(stepRun.runId);
|
const creds = this.runCredentials.get(stepRun.runId);
|
||||||
const snips = this.runSnippets.get(stepRun.runId);
|
const snips = this.runSnippets.get(stepRun.runId);
|
||||||
const env = this.runEnvironments.get(stepRun.runId);
|
const env = this.runEnvironments.get(stepRun.runId);
|
||||||
const { result: execOutput } = await this.codeExecutor.execute({
|
const execCtx = new ExecContextBuilder()
|
||||||
page,
|
.page(page)
|
||||||
browser: context,
|
.browser(context)
|
||||||
code: step.execCode,
|
.code(step.execCode)
|
||||||
log: this.stepLogger(stepRun.id, stepRun.runId),
|
.log(this.stepLogger(stepRun.id, stepRun.runId))
|
||||||
getStepOutput,
|
.getStepOutput(getStepOutput)
|
||||||
credentials: creds,
|
.credentials(creds)
|
||||||
environment: env,
|
.environment(env)
|
||||||
snippets: snips,
|
.snippets(snips)
|
||||||
});
|
.build();
|
||||||
|
const { result: execOutput } = await this.codeExecutor.execute(execCtx);
|
||||||
|
|
||||||
await this.passStepRun(stepRun, null, execOutput);
|
await this.passStepRun(stepRun, null, execOutput);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -310,7 +315,8 @@ export class ScenarioSchedulerService {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
if (remaining === 0) {
|
if (remaining === 0) {
|
||||||
await this.closeBrowserHandle(stepRun.runId);
|
// Don't close the browser here — maybePreserveSession will handle it
|
||||||
|
// (either preserving it if saveSession=true, or closing if false)
|
||||||
await this.runRepo.update(stepRun.runId, { status: "pass" });
|
await this.runRepo.update(stepRun.runId, { status: "pass" });
|
||||||
this.logger.log(`Run #${stepRun.runId} → pass (all steps passed)`);
|
this.logger.log(`Run #${stepRun.runId} → pass (all steps passed)`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ export class ScenarioService {
|
|||||||
await this.findOne(scenarioId); // 404 guard
|
await this.findOne(scenarioId); // 404 guard
|
||||||
const run = await this.runRepo.findOne({
|
const run = await this.runRepo.findOne({
|
||||||
where: { id: runId, scenarioId },
|
where: { id: runId, scenarioId },
|
||||||
relations: ["stepRuns", "stepRuns.scenarioStep"],
|
relations: ["stepRuns", "stepRuns.scenarioStep", "environment", "session"],
|
||||||
order: { stepRuns: { order: "ASC" } },
|
order: { stepRuns: { order: "ASC" } },
|
||||||
});
|
});
|
||||||
if (!run)
|
if (!run)
|
||||||
@@ -387,7 +387,7 @@ export class ScenarioService {
|
|||||||
|
|
||||||
return this.runRepo.findOne({
|
return this.runRepo.findOne({
|
||||||
where: { id: run.id },
|
where: { id: run.id },
|
||||||
relations: ["stepRuns"],
|
relations: ["stepRuns", "environment", "session"],
|
||||||
order: { stepRuns: { order: "ASC" } },
|
order: { stepRuns: { order: "ASC" } },
|
||||||
}) as Promise<ScenarioRunEntity>;
|
}) as Promise<ScenarioRunEntity>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user