Skip to content

Commit e9d2c63

Browse files
authored
fix(web-integration): reuse static UI context (#3089)
1 parent 622b944 commit e9d2c63

3 files changed

Lines changed: 75 additions & 2 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
import { Agent as PageAgent } from '@midscene/core/agent';
2+
import type { UIContext } from '@midscene/core';
23
import type StaticPage from './static-page';
34

45
export class StaticPageAgent extends PageAgent {
6+
private readonly staticPage: StaticPage;
7+
58
constructor(page: StaticPage) {
69
// Disable report generation in browser environment to avoid Node.js fs module errors
710
super(page, { generateReport: false });
11+
this.staticPage = page;
812
this.dryMode = true;
913
}
14+
15+
override async getUIContext(): Promise<UIContext> {
16+
return this.staticPage.getUIContext();
17+
}
1018
}

‎packages/web-integration/src/static/static-page.ts‎

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
ScreenshotRef,
55
UIContext,
66
} from '@midscene/core';
7+
import { ScreenshotItem } from '@midscene/core';
78
import type { AbstractInterface } from '@midscene/core/device';
89
import {
910
type InputPrimitives,
@@ -25,9 +26,12 @@ type SerializedStaticScreenshot = {
2526

2627
type StaticPageUIContext = Omit<
2728
UIContext,
28-
'deprecatedDpr' | 'screenshot'
29+
'deprecatedDpr' | 'screenshot' | 'screenshotSequence'
2930
> & {
3031
screenshot: UIContext['screenshot'] | SerializedStaticScreenshot;
32+
screenshotSequence?: Array<
33+
UIContext['screenshot'] | SerializedStaticScreenshot
34+
>;
3135
};
3236

3337
function screenshotBase64FromContext(
@@ -50,10 +54,38 @@ function screenshotBase64FromContext(
5054
);
5155
}
5256

57+
function screenshotItemFromContext(
58+
screenshot: StaticPageUIContext['screenshot'],
59+
): ScreenshotItem {
60+
if (screenshot instanceof ScreenshotItem) {
61+
return screenshot;
62+
}
63+
64+
const capturedAt =
65+
typeof screenshot.capturedAt === 'number'
66+
? screenshot.capturedAt
67+
: Date.now();
68+
return ScreenshotItem.create(
69+
screenshotBase64FromContext(screenshot),
70+
capturedAt,
71+
);
72+
}
73+
74+
function normalizeUIContext(uiContext: StaticPageUIContext): UIContext {
75+
return {
76+
...uiContext,
77+
screenshot: screenshotItemFromContext(uiContext.screenshot),
78+
screenshotSequence: uiContext.screenshotSequence?.map(
79+
screenshotItemFromContext,
80+
),
81+
};
82+
}
83+
5384
export default class StaticPage implements AbstractInterface {
5485
interfaceType = 'static';
5586

5687
private uiContext: StaticPageUIContext;
88+
private normalizedUIContext?: UIContext;
5789
readonly inputPrimitives: InputPrimitives = {
5890
pointer: {
5991
tap: async () => ThrowNotImplemented('Tap'),
@@ -78,6 +110,11 @@ export default class StaticPage implements AbstractInterface {
78110
this.uiContext = uiContext;
79111
}
80112

113+
getUIContext(): UIContext {
114+
this.normalizedUIContext ??= normalizeUIContext(this.uiContext);
115+
return this.normalizedUIContext;
116+
}
117+
81118
actionSpace(): DeviceAction[] {
82119
// Return available actions for static page - they will throw "not implemented" errors when executed
83120
// but need to be available for planning phase
@@ -175,5 +212,6 @@ export default class StaticPage implements AbstractInterface {
175212

176213
updateContext(newContext: StaticPageUIContext): void {
177214
this.uiContext = newContext;
215+
this.normalizedUIContext = undefined;
178216
}
179217
}

‎packages/web-integration/tests/unit-test/static-page.test.ts‎

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ScreenshotItem } from '@midscene/core';
22
import { describe, expect, it } from '@rstest/core';
3-
import { StaticPage } from '../../src/static';
3+
import { StaticPage, StaticPageAgent } from '../../src/static';
44

55
const screenshotBase64 = 'data:image/png;base64,abc123';
66

@@ -53,4 +53,31 @@ describe('StaticPage', () => {
5353
'serialized reference without base64 data',
5454
);
5555
});
56+
57+
it('lets StaticPageAgent reuse the prepared UI context', async () => {
58+
const capturedAt = 123;
59+
const page = new StaticPage(
60+
createContext({ base64: screenshotBase64, capturedAt }),
61+
);
62+
const agent = new StaticPageAgent(page);
63+
64+
const context = await agent.getUIContext();
65+
66+
expect(context.shotSize).toEqual({ width: 800, height: 600 });
67+
expect(context.shrunkShotToLogicalRatio).toBe(1);
68+
expect(context.screenshot).toBeInstanceOf(ScreenshotItem);
69+
expect(context.screenshot.base64).toBe(screenshotBase64);
70+
expect(context.screenshot.capturedAt).toBe(capturedAt);
71+
72+
const updatedScreenshotBase64 = 'data:image/png;base64,updated';
73+
page.updateContext(
74+
createContext({ base64: updatedScreenshotBase64, capturedAt: 456 }),
75+
);
76+
77+
const updatedContext = await agent.getUIContext();
78+
79+
expect(updatedContext).not.toBe(context);
80+
expect(updatedContext.screenshot.base64).toBe(updatedScreenshotBase64);
81+
expect(updatedContext.screenshot.capturedAt).toBe(456);
82+
});
5683
});

0 commit comments

Comments
 (0)