(
this: Playwright<TCurrent>,
mustBeChained: boolean,
nextCall: (current: TCurrent) => TNext | Promise<TNext>
)
| 670 | readonly [Symbol.toStringTag]: string = 'Playwright' |
| 671 | |
| 672 | private _chain<TNext>( |
| 673 | this: Playwright<TCurrent>, |
| 674 | mustBeChained: boolean, |
| 675 | nextCall: (current: TCurrent) => TNext | Promise<TNext> |
| 676 | ): Playwright<TNext> & Promise<TNext> { |
| 677 | const syncError = new Error('next-browser-base-chain-error') |
| 678 | |
| 679 | // If `this` is actually a proxy created by a previous chained call, it'll act like it has a `promise` property. |
| 680 | // (see proxy code below) |
| 681 | type MaybeChained<T> = Playwright<T> & { |
| 682 | promise?: Promise<T> |
| 683 | } |
| 684 | const self = this as MaybeChained<TCurrent> |
| 685 | |
| 686 | let currentPromise = self.promise |
| 687 | if (!currentPromise) { |
| 688 | if (mustBeChained) { |
| 689 | // Note that this should also be enforced by the type system |
| 690 | // by adding appropriate `(this: Playwright<PreviousValue>)` type annotations |
| 691 | // to methods that expect to be chained, but tests can bypass this (or not be checked because they use JS) |
| 692 | throw new Error( |
| 693 | 'Expected this call to be chained after a previous call' |
| 694 | ) |
| 695 | } else { |
| 696 | // We're handling a call that does not expect to be chained after a previous one, |
| 697 | // so it's safe to default the current value to undefined -- we don't need a value to invoke `nextCall` |
| 698 | currentPromise = Promise.resolve(undefined as TCurrent) |
| 699 | } |
| 700 | } |
| 701 | |
| 702 | const promise = currentPromise.then(nextCall).catch((reason: unknown) => { |
| 703 | // TODO: only patch the stacktrace if the sync callstack is missing from it |
| 704 | if (reason && typeof reason === 'object' && 'stack' in reason) { |
| 705 | const syncCallStack = syncError.stack!.split(syncError.message)[1] |
| 706 | reason.stack += `\n${syncCallStack}` |
| 707 | } |
| 708 | throw reason |
| 709 | }) |
| 710 | |
| 711 | function get(target: Playwright<TCurrent>, p: string | symbol): any { |
| 712 | switch (p) { |
| 713 | case 'promise': |
| 714 | return promise |
| 715 | case 'then': |
| 716 | return promise.then.bind(promise) |
| 717 | case 'catch': |
| 718 | return promise.catch.bind(promise) |
| 719 | case 'finally': |
| 720 | return promise.finally.bind(promise) |
| 721 | default: |
| 722 | return target[p] |
| 723 | } |
| 724 | } |
| 725 | |
| 726 | // @ts-expect-error: we're changing `TCurrent` into TNext via proxy hacks |
| 727 | return new Proxy(this, { |
| 728 | get, |
| 729 | }) |
no test coverage detected