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 () => {
|
||||
await firstDraw;
|
||||
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 });
|
||||
},
|
||||
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(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