fix: enforce elapsed loading display minimum after timer wakes
This commit is contained in:
+5
-1
@@ -81,7 +81,11 @@ export class LocalPlatformLogin extends Component {
|
|||||||
waitForMinimumDisplay: async () => {
|
waitForMinimumDisplay: async () => {
|
||||||
await firstDraw;
|
await firstDraw;
|
||||||
const drawnAt = this.required(this.firstDrawAt, 'loading first draw');
|
const drawnAt = this.required(this.firstDrawAt, 'loading first draw');
|
||||||
await this.delay(Math.max(0, MINIMUM_LOADING_MS - (performance.now() - drawnAt)));
|
let remaining = MINIMUM_LOADING_MS - (performance.now() - drawnAt);
|
||||||
|
while (remaining > 0) {
|
||||||
|
await this.delay(remaining);
|
||||||
|
remaining = MINIMUM_LOADING_MS - (performance.now() - drawnAt);
|
||||||
|
}
|
||||||
this.record({ kind: 'minimum-display-ready', data: performance.now() - drawnAt });
|
this.record({ kind: 'minimum-display-ready', data: performance.now() - drawnAt });
|
||||||
},
|
},
|
||||||
createSocket: url => new WebSocket(url), record: event => this.record(event),
|
createSocket: url => new WebSocket(url), record: event => this.record(event),
|
||||||
|
|||||||
@@ -143,3 +143,57 @@ test('component stop cancels pending draw and timer work and disables spinner up
|
|||||||
assert.equal(timers.size, 0); assert.equal(director.listenerCount('draw'), 0);
|
assert.equal(timers.size, 0); assert.equal(director.listenerCount('draw'), 0);
|
||||||
assert.equal(component.getDiagnostics().pendingCount, 0);
|
assert.equal(component.getDiagnostics().pendingCount, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('minimum display ignores an early timer wake and cancellation clears its remaining wait', async () => {
|
||||||
|
const path = new URL('../../YouleNexus/assets/scripts/local-platform-login/LocalPlatformLogin.ts', import.meta.url);
|
||||||
|
const exports: any = {}; const timers = new Map<number, () => void>(); let timerId = 0; let clock = 100;
|
||||||
|
let hostOptions: any;
|
||||||
|
runInNewContext(ts.transpileModule(readFileSync(path, 'utf8'), {
|
||||||
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, experimentalDecorators: true },
|
||||||
|
}).outputText, { exports, require: (name: string) => {
|
||||||
|
if (name === 'cc/env') return { DEBUG: true };
|
||||||
|
if (name === 'cc') return { Component: class {}, Node, Label, Sprite, UITransform, Prefab: class {}, sys: { isNative: false },
|
||||||
|
_decorator: { ccclass: () => (target: unknown) => target, property: () => () => {} } };
|
||||||
|
if (name.endsWith('local-login-host.ts')) return { createLocalLoginHost: (options: unknown) => {
|
||||||
|
hostOptions = options; return { start: async () => {}, stop() {}, getSnapshot: () => ({}) };
|
||||||
|
} };
|
||||||
|
if (name.endsWith('local-login-view.ts')) return load();
|
||||||
|
if (name.endsWith('remote-config-fetcher.ts')) return { HttpConfigFetcher: class {} };
|
||||||
|
throw new Error(`Unexpected dependency ${name}`);
|
||||||
|
}, Error, performance: { now: () => clock }, window: {
|
||||||
|
location: { search: '?profile=local' }, localStorage: {},
|
||||||
|
setTimeout: (callback: () => void) => { timers.set(++timerId, callback); return timerId; },
|
||||||
|
clearTimeout: (id: number) => timers.delete(id),
|
||||||
|
} });
|
||||||
|
async function started() {
|
||||||
|
const component = new exports.LocalPlatformLogin(); const f = fixture();
|
||||||
|
Object.assign(component, f.refs, { stopButton: new Node(), loadingPrefab: {}, loginPrefab: {} });
|
||||||
|
const loading = new Node('Layer614_Loading'); const group = new Node('group-40');
|
||||||
|
const spinner = new Node('载入动画'); spinner.components.set(Sprite, new Sprite());
|
||||||
|
spinner.components.set(UITransform, new UITransform()); group.children.push(spinner);
|
||||||
|
loading.children.push(group); component.loadingRoot.children.push(loading);
|
||||||
|
component.loadingRoot.getComponentsInChildren = () => [];
|
||||||
|
await component.start(); director.emit('draw'); await Promise.resolve();
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
const drain = async () => { for (let i = 0; i < 5; i++) await Promise.resolve(); };
|
||||||
|
function wake(at: number) {
|
||||||
|
clock = at; const [id, callback] = timers.entries().next().value!;
|
||||||
|
timers.delete(id); callback();
|
||||||
|
}
|
||||||
|
const component = await started(); let completed = false;
|
||||||
|
const minimum = hostOptions.waitForMinimumDisplay().then(() => { completed = true; });
|
||||||
|
await drain(); wake(599.8); await drain();
|
||||||
|
assert.equal(completed, false, '499.8 ms elapsed must not open minimum display gate');
|
||||||
|
assert.equal(component.getDiagnostics().events.some((event: any) => event.kind === 'minimum-display-ready'), false);
|
||||||
|
assert.equal(timers.size, 1);
|
||||||
|
wake(600); await minimum; assert.equal(completed, true); assert.equal(timers.size, 0);
|
||||||
|
component.stop();
|
||||||
|
|
||||||
|
clock = 1000; const cancelled = await started();
|
||||||
|
const cancelledMinimum = hostOptions.waitForMinimumDisplay();
|
||||||
|
const rejection = assert.rejects(cancelledMinimum, /cancelled/);
|
||||||
|
await drain(); wake(1499.8); await drain();
|
||||||
|
assert.equal(timers.size, 1); cancelled.stop(); await rejection;
|
||||||
|
assert.equal(timers.size, 0); assert.equal(cancelled.getDiagnostics().pendingCount, 0);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user