testing.FakeSessionOptions.profile ​Contract 2.0.0 · package sha256
a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e· generated fromtesting.d.tsbyservices/onsite-scripter/scripts/build-contract-docs.mjs; edit the source, not this file.
Property of testing.FakeSessionOptions · stable · since 2.0.0
profile?: {
unsupported?: readonly Capability[];
permits?: readonly string[];
tier?: InfoReport['renderer']['tier'];
linkedLights?: number;
maxTextureSize?: number;
arModes?: InfoReport['ar']['modes'];
arPending?: boolean;
arEscapeOnly?: boolean;
arEnabled?: boolean;
tryOn?: {
kinds: readonly TryOnKind[];
blocked?: 'switched-off' | 'unsupported';
outcome?: 'launched' | 'camera-denied' | 'needs-tap' | 'error' | 'other';
durationMs?: number;
};
problems?: ReadonlyArray<Omit<Problem, 'at' | 'docs'>>;
session?: {
accountId?: number;
configuratorId?: string | null;
};
};
The runtime, device and account the fake answers for (spec section 9.4). Unset, it is a
full-featured desktop: supports(), has() true for each KnownCapability the fake builds (a
member still to come, and an option the runtime takes its fallback for: false, as on the
runtime), permits()
false, tier 'high', 'ar:modes'
answered. supports(), has(), permits(), the gated operations and info() read it alike;
info().ar.enabled and info().document follow the applied documents, as in the runtime.
Default: {}
unsupported ​unsupported?: readonly Capability[];
Ids this runtime lacks: supports() and has() answer false for them.
Default: []
permits ​permits?: readonly string[];
Gated capabilities this account may use (permits()).
Default: []
tier ​tier?: InfoReport['renderer']['tier'];
info().renderer.tier.
Default: 'high'
linkedLights ​linkedLights?: number;
info().renderer.limits.linkedLights.
Default: the runtime's floor for every tier (spec section 5.15)
maxTextureSize ​maxTextureSize?: number;
info().device.maxTextureSize, px.
Default: 4096
arModes ​arModes?: InfoReport['ar']['modes'];
The device's AR modes at boot, as the runtime reads them: info().ar.fileModes is its
native part, and info().ar.modes lists it without 'scene-viewer' while the committed
product is encrypted with no public plain twin, as the runtime's (a call with an http(s)
glbUrl opens Scene Viewer where this lists it).
Default: []
arPending ​arPending?: boolean;
info().ar.pending at boot; setArModes answers it.
Default: false
arEscapeOnly ​arEscapeOnly?: boolean;
The in-page route is the escape sheet only (an app shell not yet measured, a host's deny
row; DL50): info().ar.modes lists 'webxr' as set in arModes, and activateAR() opens
the sheet, resolving { launched: false, reason: 'unsupported' } with no 'ar:status'
(the sheet is the message), 'webxr' still listed, as on the runtime.
Default: false
arEnabled ​arEnabled?: boolean;
info().ar.enabled: false is an account (or document) with AR off. info().ar.modes is
then empty and activateAR() resolves { launched: false, reason: 'disabled' } with
'ar:status' 'disabled', as in the runtime.
Default: true
tryOn ​tryOn?: { … }
The account's try-on, so a wearable page tests its Try-on control. Unset, the account
offers none: canTryOn() answers { available: false, kind: 'other', modes: [], reason: 'not-enabled' } and tryOn() resolves 'unavailable'. Set, canTryOn() follows the
committed product's rig as the runtime does, re-read after each commit: the first
enabled ModelNode with a stored tryOn record (a GroupNode's active child, by
defaultNodeId) gives kind; a kind kinds lacks answers 'not-enabled', then blocked,
then a kind with no tracker in this runtime (every kind but 'face' today) 'unsupported',
then a node without a tryOnUrl and an approved rig of a format the runtime reads
(tryOn.approved.format 1), or no such node, 'no-rig'; else { available: true, kind, modes: ['here', 'handoff'] } (blocked: 'unsupported' with such a rig lists
['handoff']). tryOn() then resolves as the runtime's: 'unavailable' (mode 'other';
'unsupported' where canTryOn() says 'unsupported') when it can't open, 'unsupported' for
ui: 'headless'; mode: 'handoff' opens where modes lists it and resolves { launched: true, mode: 'handoff', handoffUrl } after durationMs whatever outcome says (no camera
opens here), its link returnUrl read against the page's address ('unsupported' with
neither, as in Node); else outcome after durationMs; a call while one is open returns
its Promise, endAR() closes it at once (durationMs the time it ran; an unlaunched
outcome closes as 'other'), and an aborted signal rejects AbortError. No 'xr:start' or
'xr:end' fires (no camera opens). The profile's example runs a Try-on control.
Default: undefined (no try-on)
tryOn.kinds ​kinds: readonly TryOnKind[];
The kinds the account offers, its consent mode set.
tryOn.blocked ​blocked?: 'switched-off' | 'unsupported';
'switched-off' (Holostep switched try-on off) or 'unsupported' (this device: no camera, or the page blocks it).
Default: undefined (neither)
tryOn.outcome ​outcome?: 'launched' | 'camera-denied' | 'needs-tap' | 'error' | 'other';
How a try-on that opens ends: 'launched' (the camera picture showed), else the reason it closed without it.
Default: 'launched'
tryOn.durationMs ​durationMs?: number;
Fake-clock ms from the call to the close ('needs-tap' answers at once).
Default: 0
problems ​problems?: ReadonlyArray<Omit<Problem, 'at' | 'docs'>>;
Problems boot would record before it resolves, such as 'tenant-document-unavailable'
(spec section 5.1): in problems() and info().problems from the start, and dispatched to
no handler, as the runtime's are.
Default: []
session ​session?: { … }
info().session's ids.
Default: {}
session.accountId ​accountId?: number;
info().session.accountId.
Default: 0
session.configuratorId ​configuratorId?: string | null;
info().session.configuratorId.
Default: null
Imports: values (has, validate, the Holo*Error classes, the pure helpers) from @holostep-configurators/runtime-client, types from @holostep-configurators/runtime-client/contract, /math and /testing names from those entries; boot from the runtime module the root's loadRuntimeAtFloor resolves to. A type your page defines is your app's: declare it there, never import it from the package.
Compiled under the contract's strict settings (examples/declaration/24-FakeSessionOptions.profile.ts):
import { createFakeSession } from '@holostep-configurators/runtime-client/testing';
import type { IModelNode, Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
// A glasses page shows its Try-on button only where try-on can open, and tells the
// shopper when the camera was refused.
declare const aviator: IModelNode; // glbUrl 'glasses.glb', an approved 'face' rig (tryOn, tryOnUrl)
const fake = createFakeSession({
models: { 'glasses.glb': { nodes: [{ name: 'Frame', mesh: true }] } },
root: [aviator],
profile: { tryOn: { kinds: ['face'], outcome: 'camera-denied', durationMs: 400 } },
});
let loaded = false;
void fake.idle().then(() => (loaded = true));
for (let i = 0; i < 100 && !loaded; i++) {
fake.tick(16);
await new Promise((resolve) => setTimeout(resolve, 0));
}
export const button = { shown: fake.canTryOn?.().available === true };
const closed = fake.tryOn?.();
fake.tick(400); // the shopper refuses the camera
export const report = await closed;
if (!button.shown || report?.reason !== 'camera-denied') {
throw new Error('the Try-on control did not follow the account and the product');
}
| Rule | Result |
|---|---|
| 1. Neutral name | pass: profile names no product |
| 2. A precedent | not recorded: no ledger row (coverage.json) names this member or its owner |
| 3. Two apps, or labs | not recorded: no ledger row names this member or its owner |
| 4. The cheaper fix first | not recorded per member (Appendix B decides it per need) |