@enekesabel/playwright-lite 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +20 -22
  2. package/dist/index.mjs +767 -195
  3. package/package.json +6 -6
package/dist/index.mjs CHANGED
@@ -480,20 +480,198 @@ var UtilityScript$1 = class {
480
480
  };
481
481
  const LiteUtilityScript = module$1.exports.UtilityScript();
482
482
  //#endregion
483
+ //#region src/jsHandle.ts
484
+ const invalidArguments = "Too many arguments. If you need to pass more than 1 argument to the function wrap them in an object.";
485
+ function assertEvaluationOptions(options) {
486
+ if (options !== void 0 && (typeof options !== "object" || options === null || Array.isArray(options))) throw new Error(invalidArguments);
487
+ if (options?.exposeFunctions === true) throw new Error("Unsupported Playwright option: evaluate.exposeFunctions");
488
+ if (options?.exposeFunctions !== void 0 && typeof options.exposeFunctions !== "boolean") throw new Error("exposeFunctions must be a boolean");
489
+ }
490
+ function assertMaxArguments(count, maximum) {
491
+ if (count > maximum) throw new Error(invalidArguments);
492
+ }
493
+ /**
494
+ * A reference to one value in the controlled document.
495
+ *
496
+ * Mirrors pinned 26a9e47 client/jsHandle.ts and server/javascript.ts: the value
497
+ * never leaves the document, and every member either evaluates against it or
498
+ * copies it out through the pinned serializers.
499
+ */
500
+ var AdapterJSHandle = class {
501
+ value;
502
+ evaluation;
503
+ disposedError = "JSHandle is disposed!";
504
+ disposed = false;
505
+ preview;
506
+ constructor(value, evaluation) {
507
+ this.value = value;
508
+ this.evaluation = evaluation;
509
+ }
510
+ /** Internal boundary used by evaluation argument and target unwrapping. */
511
+ valueForEvaluation(evaluation) {
512
+ if (this.evaluation !== evaluation) throw new Error("JSHandles can be evaluated only in the context they were created!");
513
+ if (this.disposed) throw new Error(this.disposedError);
514
+ return this.value;
515
+ }
516
+ asElement() {
517
+ return null;
518
+ }
519
+ async evaluate(pageFunction, arg, options) {
520
+ assertMaxArguments(arguments.length, 3);
521
+ assertEvaluationOptions(options);
522
+ return this.evaluation.byValue(pageFunction, typeof pageFunction === "function", arg, this);
523
+ }
524
+ async evaluateHandle(pageFunction, arg, options) {
525
+ assertMaxArguments(arguments.length, 3);
526
+ assertEvaluationOptions(options);
527
+ return this.evaluation.byHandle(pageFunction, typeof pageFunction === "function", arg, this);
528
+ }
529
+ /** Pinned javascript.ts:188 reads the property off the value itself. */
530
+ async getProperty(propertyName) {
531
+ const value = this.valueForEvaluation(this.evaluation);
532
+ return this.evaluation.handleFor(value[propertyName]);
533
+ }
534
+ /**
535
+ * Pinned crExecutionContext.ts:75 lists own enumerable data properties, and
536
+ * javascript.ts:197 answers with an empty map for a value without an object.
537
+ */
538
+ async getProperties() {
539
+ const value = this.valueForEvaluation(this.evaluation);
540
+ const properties = /* @__PURE__ */ new Map();
541
+ if (value === null || typeof value !== "object" && typeof value !== "function") return properties;
542
+ for (const name of Object.getOwnPropertyNames(value)) {
543
+ const descriptor = Object.getOwnPropertyDescriptor(value, name);
544
+ if (!descriptor?.enumerable || !("value" in descriptor)) continue;
545
+ properties.set(name, this.evaluation.handleFor(descriptor.value));
546
+ }
547
+ return properties;
548
+ }
549
+ async jsonValue() {
550
+ return this.evaluation.jsonValue(this.valueForEvaluation(this.evaluation));
551
+ }
552
+ async dispose() {
553
+ this.toString();
554
+ this.disposed = true;
555
+ this.value = void 0;
556
+ }
557
+ async [Symbol.asyncDispose]() {
558
+ await this.dispose();
559
+ }
560
+ toString() {
561
+ return this.preview ??= this.computePreview();
562
+ }
563
+ computePreview() {
564
+ return previewValue(this.value);
565
+ }
566
+ };
567
+ /**
568
+ * Mirrors the handle preview pinned 26a9e47 crExecutionContext.ts:123
569
+ * (`renderPreview`) derives from a Chromium remote object: a value that crosses
570
+ * the protocol renders as `String(value)`, and an object renders as V8's
571
+ * `RemoteObject.description`. Handles created inside the document carry no
572
+ * remote object, so the description is reconstructed from the value.
573
+ */
574
+ function previewValue(value) {
575
+ if (value === null) return "null";
576
+ if (typeof value === "bigint") return `${value}n`;
577
+ if (typeof value === "function") return String(value);
578
+ if (typeof value !== "object") return Object.is(value, -0) ? "-0" : String(value);
579
+ const tag = Object.prototype.toString.call(value).slice(8, -1);
580
+ if (tag === "Date" || tag === "RegExp") return String(value);
581
+ if (tag === "Error") return value.stack || String(value);
582
+ const name = tag === "Object" ? constructorName(value) : tag;
583
+ if (tag === "Map" || tag === "Set") return `${name}(${value.size})`;
584
+ if (tag === "Array" || ArrayBuffer.isView(value)) return `${name}(${value.length})`;
585
+ return name;
586
+ }
587
+ function constructorName(value) {
588
+ return value.constructor?.name || "Object";
589
+ }
590
+ //#endregion
591
+ //#region src/protocolValidation.ts
592
+ /**
593
+ * Client-boundary checks from the pinned Playwright protocol semantics.
594
+ * See packages/protocol/src/validatorPrimitives.ts and spec/frame.yml at
595
+ * 26a9e470a7b3c7822084b09fb7f13902c5f37b51.
596
+ */
597
+ function validateString(value, name) {
598
+ if (value instanceof String) return value.valueOf();
599
+ if (typeof value === "string") return value;
600
+ throw new Error(`${name}: expected string, got ${typeof value}`);
601
+ }
602
+ function validateInteger(value, name) {
603
+ const integer = value instanceof Number ? value.valueOf() : value;
604
+ if (typeof integer !== "number") throw new Error(`${name}: expected integer, got ${typeof value}`);
605
+ if (!Number.isInteger(integer)) throw new Error(`${name}: expected integer, got float ${integer}`);
606
+ return integer;
607
+ }
608
+ /**
609
+ * `delay` is `float?` in the pinned protocol for press, type and the pointer
610
+ * actions. Like the pointer options, a non-finite value is rejected instead of
611
+ * reaching the input path as NaN, and a boxed `Number` is unwrapped for the
612
+ * caller to forward instead of leaking an object into the input path.
613
+ */
614
+ function validateDelay(value) {
615
+ if (value === void 0) return void 0;
616
+ const delay = value instanceof Number ? value.valueOf() : value;
617
+ if (typeof delay !== "number" || !Number.isFinite(delay)) throw new TypeError("delay: expected number");
618
+ return delay;
619
+ }
620
+ /**
621
+ * `force` is `boolean?` in the pinned protocol for every action that takes it.
622
+ * Like the pointer options, a boxed `Boolean` is unwrapped so the caller
623
+ * forwards a primitive instead of an always-truthy object.
624
+ */
625
+ function validateForce(method, value) {
626
+ if (value === void 0) return void 0;
627
+ const force = value instanceof Boolean ? value.valueOf() : value;
628
+ if (typeof force !== "boolean") throw new TypeError(`${method} force must be a boolean`);
629
+ return force;
630
+ }
631
+ /**
632
+ * `signal` is a client-side option in the pinned API: it never reaches the
633
+ * protocol, so the adapter checks the value itself. `name` is the API member
634
+ * or option group the message speaks for, such as `click` or `Query`.
635
+ */
636
+ function validateSignal(name, value) {
637
+ if (value === void 0 || value instanceof AbortSignal) return;
638
+ throw new TypeError(`${name} signal must be an AbortSignal`);
639
+ }
640
+ /**
641
+ * Rejects options the adapter does not implement, shared by the `Locator` and
642
+ * `ElementHandle` forms of a member so both reject the same option with the
643
+ * same message. Returns the normalized `delay`, unwrapped like the pointer
644
+ * options.
645
+ */
646
+ function rejectUnsupportedOptions(method, options, supported = []) {
647
+ if (!options) return void 0;
648
+ const unsupported = Object.keys(options).filter((key) => options[key] !== void 0 && !supported.includes(key));
649
+ if (unsupported.length > 0) throw new Error(`${method}(): unsupported Playwright option(s): ${unsupported.join(", ")}.`);
650
+ validateSignal(method, options.signal);
651
+ if (supported.includes("noWaitAfter")) validateNoWaitAfter(method, options.noWaitAfter);
652
+ return supported.includes("delay") ? validateDelay(options.delay) : void 0;
653
+ }
654
+ function validateNoWaitAfter(method, value) {
655
+ if (method !== "click" && method !== "press") return;
656
+ if (value === void 0 || typeof value === "boolean" || value instanceof Boolean) return;
657
+ throw new Error(`noWaitAfter: expected boolean, got ${typeof value}`);
658
+ }
659
+ //#endregion
483
660
  //#region src/elementHandle.ts
484
661
  /**
485
- * A browser-native, fixed reference to one element in the controlled document.
662
+ * A browser-native, fixed reference to one node in the controlled document.
486
663
  *
487
- * This deliberately is not a Locator: selector operations below remain scoped
488
- * to `element`, even after the document replaces a matching node.
664
+ * Pinned dom.ts:120 derives ElementHandle from JSHandle; the node members below
665
+ * extend the handle members with it. This deliberately is not a Locator:
666
+ * selector operations remain scoped to `element`, even after the document
667
+ * replaces a matching node.
489
668
  */
490
- var AdapterElementHandle = class {
669
+ var AdapterElementHandle = class extends AdapterJSHandle {
491
670
  ownerPage;
492
- element;
493
- disposed = false;
671
+ disposedError = "ElementHandle has been disposed";
494
672
  constructor(ownerPage, element) {
673
+ super(element, ownerPage.evaluation);
495
674
  this.ownerPage = ownerPage;
496
- this.element = element;
497
675
  }
498
676
  async click(options) {
499
677
  await this.ownerPage.clickSelector(this.requireElement(), "elementHandle.click", options?.timeout, void 0, options);
@@ -505,14 +683,79 @@ var AdapterElementHandle = class {
505
683
  await this.ownerPage.hoverSelector(this.requireElement(), "elementHandle.hover", options?.timeout, void 0, options);
506
684
  }
507
685
  async check(options) {
508
- await this.ownerPage.setCheckedSelector(this.requireElement(), true, "elementHandle.check", options);
686
+ await this.ownerPage.setCheckedSelector(this.requireElement(), true, "elementHandle.check", options, void 0, "check");
509
687
  }
510
688
  async uncheck(options) {
511
- await this.ownerPage.setCheckedSelector(this.requireElement(), false, "elementHandle.uncheck", options);
689
+ await this.ownerPage.setCheckedSelector(this.requireElement(), false, "elementHandle.uncheck", options, void 0, "uncheck");
512
690
  }
513
691
  async setChecked(checked, options) {
514
692
  await this.ownerPage.setCheckedSelector(this.requireElement(), checked, "elementHandle.setChecked", options);
515
693
  }
694
+ async fill(value, options) {
695
+ rejectUnsupportedOptions("fill", options, [
696
+ "force",
697
+ "noWaitAfter",
698
+ "signal",
699
+ "timeout"
700
+ ]);
701
+ const force = validateForce("fill", options?.force);
702
+ await withAbortPrefix("elementHandle.fill", () => this.ownerPage.fillSelector(this.requireElement(), value, "elementHandle.fill", options?.timeout, void 0, true, options?.signal, "fill", force));
703
+ }
704
+ async focus() {
705
+ await this.ownerPage.focusSelector(this.requireElement(), "elementHandle.focus");
706
+ }
707
+ async type(text, options) {
708
+ rejectUnsupportedOptions("type", options, [
709
+ "delay",
710
+ "noWaitAfter",
711
+ "signal",
712
+ "timeout"
713
+ ]);
714
+ await withAbortPrefix("elementHandle.type", () => this.ownerPage.typeSelector(this.requireElement(), text, options, "elementHandle.type", true));
715
+ }
716
+ async selectOption(values, options) {
717
+ rejectUnsupportedOptions("selectOption", options, [
718
+ "force",
719
+ "noWaitAfter",
720
+ "signal",
721
+ "timeout"
722
+ ]);
723
+ const force = validateForce("selectOption", options?.force);
724
+ return withAbortPrefix("elementHandle.selectOption", () => this.ownerPage.selectOptionSelector(this.requireElement(), values, "elementHandle.selectOption", options?.timeout, void 0, true, options?.signal, force));
725
+ }
726
+ async setInputFiles(files, options) {
727
+ rejectUnsupportedOptions("setInputFiles", options, [
728
+ "noWaitAfter",
729
+ "signal",
730
+ "timeout"
731
+ ]);
732
+ await withAbortPrefix("elementHandle.setInputFiles", () => this.ownerPage.setInputFilesSelector(this.requireElement(), files, options, true, "elementHandle.setInputFiles"));
733
+ }
734
+ async dispatchEvent(type, eventInit = {}) {
735
+ await this.ownerPage.dispatchEventSelector(this.requireElement(), type, eventInit, "elementHandle.dispatchEvent");
736
+ }
737
+ async press(key, options) {
738
+ const delay = rejectUnsupportedOptions("press", options, [
739
+ "delay",
740
+ "noWaitAfter",
741
+ "signal",
742
+ "timeout"
743
+ ]);
744
+ await withAbortPrefix("elementHandle.press", () => this.ownerPage.pressSelector(this.requireElement(), key, "elementHandle.press", options?.timeout, void 0, true, options?.signal, delay));
745
+ }
746
+ async selectText(options) {
747
+ rejectUnsupportedOptions("selectText", options, [
748
+ "force",
749
+ "signal",
750
+ "timeout"
751
+ ]);
752
+ const force = validateForce("selectText", options?.force);
753
+ await withAbortPrefix("elementHandle.selectText", () => this.ownerPage.selectText(this.requireElement(), "elementHandle.selectText", options?.timeout, void 0, options?.signal, force));
754
+ }
755
+ async scrollIntoViewIfNeeded(options) {
756
+ rejectUnsupportedOptions("scrollIntoViewIfNeeded", options, ["signal", "timeout"]);
757
+ await withAbortPrefix("elementHandle.scrollIntoViewIfNeeded", () => this.ownerPage.scrollLocatorIntoView(this.requireElement(), "elementHandle.scrollIntoViewIfNeeded", options?.timeout, void 0, options?.signal));
758
+ }
516
759
  async $(selector) {
517
760
  return this.ownerPage.elementHandleFor(this.ownerPage.resolveWithinElement(this.requireElement(), selector, false));
518
761
  }
@@ -534,6 +777,10 @@ var AdapterElementHandle = class {
534
777
  assertEvaluationOptions(options);
535
778
  return this.ownerPage.evaluation.byValue(pageFunction, typeof pageFunction === "function", arg, this.requireElement());
536
779
  }
780
+ /** Kept here so releasing a node is attributed to ElementHandle. */
781
+ async dispose() {
782
+ await super.dispose();
783
+ }
537
784
  async textContent() {
538
785
  return this.requireElement().textContent;
539
786
  }
@@ -554,6 +801,14 @@ var AdapterElementHandle = class {
554
801
  asElement() {
555
802
  return this;
556
803
  }
804
+ /** Pinned dom.ts:135 previews a node through the injected script. */
805
+ computePreview() {
806
+ try {
807
+ return `JSHandle@${this.ownerPage.previewNode(this.requireElement())}`;
808
+ } catch {
809
+ return "JSHandle@node";
810
+ }
811
+ }
557
812
  async isEnabled() {
558
813
  return this.ownerPage.elementStateForHandle(this.requireElement(), "enabled");
559
814
  }
@@ -578,43 +833,30 @@ var AdapterElementHandle = class {
578
833
  return this.ownerPage.boundingBoxForElement(this.requireElement());
579
834
  }
580
835
  async waitForElementState(state, options = {}) {
581
- await this.ownerPage.waitForElementState(this.requireElement(), state, options);
836
+ await withAbortPrefix("elementHandle.waitForElementState", () => this.ownerPage.waitForElementState(this.requireElement(), state, options));
582
837
  }
583
838
  async waitForSelector(selector, options = {}) {
584
839
  return await this.ownerPage.waitForSelectorWithinElement(this.requireElement(), selector, options);
585
840
  }
586
- async dispose() {
587
- this.disposed = true;
588
- this.element = void 0;
589
- }
590
- /** Internal boundary used only by Page evaluation argument unwrapping. */
591
- elementForEvaluation(ownerPage) {
592
- if (ownerPage !== this.ownerPage) throw new Error("ElementHandle belongs to a different Page");
593
- return this.requireElement();
594
- }
595
841
  requireElement() {
596
- if (this.disposed) throw new Error("ElementHandle has been disposed");
597
- if (!this.element) throw new Error("ElementHandle has been disposed");
598
- return this.element;
842
+ return this.valueForEvaluation(this.ownerPage.evaluation);
599
843
  }
600
844
  };
601
845
  //#endregion
602
846
  //#region src/evaluation.ts
603
- const invalidArguments = "Too many arguments. If you need to pass more than 1 argument to the function wrap them in an object.";
604
- function assertEvaluationOptions(options) {
605
- if (options !== void 0 && (typeof options !== "object" || options === null || Array.isArray(options))) throw new Error(invalidArguments);
606
- if (options?.exposeFunctions === true) throw new Error("Unsupported Playwright option: evaluate.exposeFunctions");
607
- if (options?.exposeFunctions !== void 0 && typeof options.exposeFunctions !== "boolean") throw new Error("exposeFunctions must be a boolean");
608
- }
609
- function assertMaxArguments(count, maximum) {
610
- if (count > maximum) throw new Error(invalidArguments);
611
- }
612
847
  /** Uses the pinned UtilityScript for by-value calls without a browser protocol. */
613
848
  var Evaluation = class {
614
849
  page;
615
850
  utility;
851
+ /**
852
+ * The pinned protocol reports a node as a remote-object subtype. In the
853
+ * document that test is `instanceof Node`, so the constructor is captured
854
+ * before a page script can delete the global.
855
+ */
856
+ node;
616
857
  constructor(page) {
617
858
  this.page = page;
859
+ this.node = page.window.Node;
618
860
  }
619
861
  get script() {
620
862
  return this.utility ??= new LiteUtilityScript(this.page.window, false);
@@ -622,7 +864,7 @@ var Evaluation = class {
622
864
  argument(value) {
623
865
  const references = [];
624
866
  const protocolValue = serializeValue(value, (candidate) => {
625
- if (candidate instanceof AdapterElementHandle || candidate instanceof AdapterJSHandle) {
867
+ if (candidate instanceof AdapterJSHandle) {
626
868
  references.push(candidate);
627
869
  return { h: references.length - 1 };
628
870
  }
@@ -632,10 +874,6 @@ var Evaluation = class {
632
874
  const handles = [];
633
875
  return {
634
876
  serialized: serializeAsCallArgument$1(copy, (candidate) => {
635
- if (candidate instanceof AdapterElementHandle) {
636
- handles.push(candidate.elementForEvaluation(this.page));
637
- return { h: handles.length - 1 };
638
- }
639
877
  if (candidate instanceof AdapterJSHandle) {
640
878
  handles.push(candidate.valueForEvaluation(this));
641
879
  return { h: handles.length - 1 };
@@ -645,31 +883,57 @@ var Evaluation = class {
645
883
  handles
646
884
  };
647
885
  }
886
+ /** Replaces the handles inside a protocol argument with their values. */
887
+ unwrapHandles(value) {
888
+ const { serialized, handles } = this.argument(value);
889
+ return parseEvaluationResultValue$1(serialized, handles);
890
+ }
891
+ /** Pinned crExecutionContext.ts:142 answers a node with an ElementHandle. */
892
+ handleFor(value) {
893
+ return value instanceof this.node ? new AdapterElementHandle(this.page, value) : new AdapterJSHandle(value, this);
894
+ }
648
895
  async byValue(expression, isFunction, arg, target) {
896
+ return protocolResult(parseEvaluationResultValue$1(await this.run(expression, isFunction, true, arg, target)));
897
+ }
898
+ /**
899
+ * Pinned javascript.ts:249 evaluates with `returnByValue: false`, and the
900
+ * protocol's `awaitPromise` settles a returned promise before it hands back
901
+ * the handle.
902
+ */
903
+ async byHandle(expression, isFunction, arg, target) {
904
+ return this.handleFor(await this.run(expression, isFunction, false, arg, target));
905
+ }
906
+ async run(expression, isFunction, returnByValue, arg, target) {
649
907
  const normalized = normalizeExpression(String(expression), isFunction);
650
908
  const { serialized, handles } = this.argument(arg);
651
909
  const parameters = [serialized];
652
910
  if (target !== void 0) {
653
- handles.push(target);
911
+ handles.push(target instanceof AdapterJSHandle ? target.valueForEvaluation(this) : target);
654
912
  parameters.unshift({ h: handles.length - 1 });
655
913
  }
656
914
  try {
657
- return protocolResult(parseEvaluationResultValue$1(await this.script.evaluate(isFunction, true, normalized, parameters.length, ...parameters, ...handles)));
915
+ return await this.script.evaluate(isFunction, returnByValue, normalized, parameters.length, ...parameters, ...handles);
658
916
  } catch (error) {
659
917
  throw evaluationError(error);
660
918
  }
661
919
  }
662
- /** Deserialize once, retaining predicate argument state across polls. */
920
+ /**
921
+ * Deserialize once, retaining predicate argument state across polls.
922
+ *
923
+ * The returned poll accepts the element a `Locator` predicate is called on,
924
+ * which the pinned element form passes ahead of the argument
925
+ * (`server/frames.ts` `waitForFunctionExpressionOnElement`).
926
+ */
663
927
  predicate(expression, isFunction, arg) {
664
928
  const normalized = normalizeExpression(String(expression), isFunction);
665
929
  const { serialized, handles } = this.argument(arg);
666
930
  const argument = parseEvaluationResultValue$1(serialized, handles);
667
931
  let callback;
668
- return () => {
932
+ return (target) => {
669
933
  try {
670
934
  const result = callback ?? this.page.window.eval(normalized);
671
935
  if (isFunction) callback = result;
672
- const value = isFunction ? callback(argument) : result;
936
+ const value = isFunction ? callback(...target === void 0 ? [argument] : [target, argument]) : result;
673
937
  if (value && typeof value.then === "function") return Promise.resolve(value).catch((error) => {
674
938
  throw evaluationError(error);
675
939
  });
@@ -704,28 +968,6 @@ function normalizeExpression(expression, isFunction) {
704
968
  function evaluationError(error) {
705
969
  return new Error(error instanceof Error ? error.stack || String(error) : String(error));
706
970
  }
707
- /** The existing waitForFunction handle. Additional JSHandle methods are unsupported. */
708
- var AdapterJSHandle = class {
709
- value;
710
- evaluation;
711
- disposed = false;
712
- constructor(value, evaluation) {
713
- this.value = value;
714
- this.evaluation = evaluation;
715
- }
716
- valueForEvaluation(evaluation) {
717
- if (this.evaluation !== evaluation) throw new Error("JSHandles can be evaluated only in the context they were created!");
718
- if (this.disposed) throw new Error("JSHandle is disposed!");
719
- return this.value;
720
- }
721
- async jsonValue() {
722
- return this.evaluation.jsonValue(this.valueForEvaluation(this.evaluation));
723
- }
724
- async dispose() {
725
- this.disposed = true;
726
- this.value = void 0;
727
- }
728
- };
729
971
  //#endregion
730
972
  //#region node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/nodes/identity.js
731
973
  const ALIAS = Symbol.for("yaml.alias");
@@ -14743,58 +14985,23 @@ var AdapterTimeoutError = class extends Error {
14743
14985
  }
14744
14986
  };
14745
14987
  //#endregion
14746
- //#region src/protocolValidation.ts
14747
- /**
14748
- * Client-boundary checks from the pinned Playwright protocol semantics.
14749
- * See packages/protocol/src/validatorPrimitives.ts and spec/frame.yml at
14750
- * 26a9e470a7b3c7822084b09fb7f13902c5f37b51.
14751
- */
14752
- function validateString(value, name) {
14753
- if (value instanceof String) return value.valueOf();
14754
- if (typeof value === "string") return value;
14755
- throw new Error(`${name}: expected string, got ${typeof value}`);
14756
- }
14757
- /**
14758
- * `delay` is `float?` in the pinned protocol for press, type and the pointer
14759
- * actions. Like the pointer options, a non-finite value is rejected instead of
14760
- * reaching the input path as NaN, and a boxed `Number` is unwrapped for the
14761
- * caller to forward instead of leaking an object into the input path.
14762
- */
14763
- function validateDelay(value) {
14764
- if (value === void 0) return void 0;
14765
- const delay = value instanceof Number ? value.valueOf() : value;
14766
- if (typeof delay !== "number" || !Number.isFinite(delay)) throw new TypeError("delay: expected number");
14767
- return delay;
14768
- }
14769
- /**
14770
- * `signal` is a client-side option in the pinned API: it never reaches the
14771
- * protocol, so the adapter checks the value itself. `name` is the API member
14772
- * or option group the message speaks for, such as `click` or `Query`.
14773
- */
14774
- function validateSignal(name, value) {
14775
- if (value === void 0 || value instanceof AbortSignal) return;
14776
- throw new TypeError(`${name} signal must be an AbortSignal`);
14777
- }
14778
- function validateNoWaitAfter(method, value) {
14779
- if (method !== "click" && method !== "press") return;
14780
- if (value === void 0 || typeof value === "boolean" || value instanceof Boolean) return;
14781
- throw new Error(`noWaitAfter: expected boolean, got ${typeof value}`);
14782
- }
14783
- //#endregion
14784
14988
  //#region src/inputFiles.ts
14785
14989
  /**
14786
14990
  * Pinned 26a9e47 client/elementHandle.ts converts payloads before resolving the
14787
14991
  * input; server/fileUploadUtils.ts encodes the bytes for InjectedScript. Keep
14788
14992
  * that format without importing Node's Buffer or filesystem into the browser.
14993
+ *
14994
+ * `Locator.drop` carries the same converted payloads in the pinned client, so
14995
+ * `method` names the member whose message a rejected payload belongs to.
14789
14996
  */
14790
- function inputFilePayloads(files) {
14997
+ function inputFilePayloads(files, method = "setInputFiles") {
14791
14998
  const items = Array.isArray(files) ? files : [files];
14792
- if (items.some((item) => typeof item === "string")) throw new Error("setInputFiles: file paths are not supported; pass in-memory Playwright payloads.");
14999
+ if (items.some((item) => typeof item === "string")) throw new Error(`${method}: file paths are not supported; pass in-memory Playwright payloads.`);
14793
15000
  const payloads = items.map((item) => {
14794
- if (!item || typeof item === "string" || item instanceof Blob || typeof item.name !== "string" || typeof item.mimeType !== "string" || !item.mimeType || !(item.buffer instanceof Uint8Array)) throw new TypeError("setInputFiles: expected { name, mimeType, buffer } with a non-empty MIME type and byte buffer; File and Blob are not supported.");
15001
+ if (!item || typeof item === "string" || item instanceof Blob || typeof item.name !== "string" || typeof item.mimeType !== "string" || !item.mimeType || !(item.buffer instanceof Uint8Array)) throw new TypeError(`${method}: expected { name, mimeType, buffer } with a non-empty MIME type and byte buffer; File and Blob are not supported.`);
14795
15002
  return item;
14796
15003
  });
14797
- if (payloads.reduce((size, item) => size + item.buffer.byteLength, 0) >= 52428800) throw new Error("setInputFiles: in-memory payloads must total less than 50Mb.");
15004
+ if (payloads.reduce((size, item) => size + item.buffer.byteLength, 0) >= 52428800) throw new Error(`${method}: in-memory payloads must total less than 50Mb.`);
14798
15005
  return payloads.map((item) => {
14799
15006
  let binary = "";
14800
15007
  for (let offset = 0; offset < item.buffer.byteLength; offset += 8192) binary += String.fromCharCode(...item.buffer.subarray(offset, offset + 8192));
@@ -15664,6 +15871,10 @@ var LocatorImpl = class LocatorImpl {
15664
15871
  assertMaxArguments(arguments.length, 3);
15665
15872
  return withAbortPrefix("locator.evaluate", () => this.ownerPage.locatorEvaluate(this.selector, this.label, pageFunction, arg, options));
15666
15873
  }
15874
+ async evaluateHandle(pageFunction, arg, options) {
15875
+ assertMaxArguments(arguments.length, 3);
15876
+ return withAbortPrefix("locator.evaluateHandle", () => this.ownerPage.locatorEvaluateHandle(this.selector, this.label, pageFunction, arg, options));
15877
+ }
15667
15878
  async evaluateAll(pageFunction, arg) {
15668
15879
  assertMaxArguments(arguments.length, 2);
15669
15880
  return this.ownerPage.$$eval(this.selector, pageFunction, arg);
@@ -15676,11 +15887,13 @@ var LocatorImpl = class LocatorImpl {
15676
15887
  }
15677
15888
  async fill(value, options) {
15678
15889
  rejectUnsupportedOptions("fill", options, [
15890
+ "force",
15679
15891
  "noWaitAfter",
15680
15892
  "signal",
15681
15893
  "timeout"
15682
15894
  ]);
15683
- await withAbortPrefix("locator.fill", () => this.ownerPage.fillSelector(this.selector, value, this.label, options?.timeout, void 0, true, options?.signal));
15895
+ const force = validateForce("fill", options?.force);
15896
+ await withAbortPrefix("locator.fill", () => this.ownerPage.fillSelector(this.selector, value, this.label, options?.timeout, void 0, true, options?.signal, "fill", force));
15684
15897
  }
15685
15898
  async setInputFiles(files, options) {
15686
15899
  rejectUnsupportedOptions("setInputFiles", options, [
@@ -15690,6 +15903,9 @@ var LocatorImpl = class LocatorImpl {
15690
15903
  ]);
15691
15904
  await withAbortPrefix("locator.setInputFiles", () => this.ownerPage.setInputFilesSelector(this.selector, files, options, true));
15692
15905
  }
15906
+ async drop(payload, options) {
15907
+ await this.ownerPage.dropSelector(this.selector, this.label, payload, options);
15908
+ }
15693
15909
  async press(key, options) {
15694
15910
  const delay = rejectUnsupportedOptions("press", options, [
15695
15911
  "delay",
@@ -15709,11 +15925,13 @@ var LocatorImpl = class LocatorImpl {
15709
15925
  }
15710
15926
  async clear(options) {
15711
15927
  rejectUnsupportedOptions("clear", options, [
15928
+ "force",
15712
15929
  "noWaitAfter",
15713
15930
  "signal",
15714
15931
  "timeout"
15715
15932
  ]);
15716
- await withAbortPrefix("locator.clear", () => this.ownerPage.fillSelector(this.selector, "", this.label, options?.timeout, void 0, true, options?.signal));
15933
+ const force = validateForce("clear", options?.force);
15934
+ await withAbortPrefix("locator.clear", () => this.ownerPage.fillSelector(this.selector, "", this.label, options?.timeout, void 0, true, options?.signal, "clear", force));
15717
15935
  }
15718
15936
  async hover(options) {
15719
15937
  await this.ownerPage.hoverSelector(this.selector, this.label, options?.timeout, void 0, {
@@ -15751,15 +15969,22 @@ var LocatorImpl = class LocatorImpl {
15751
15969
  }
15752
15970
  async selectOption(values, options) {
15753
15971
  rejectUnsupportedOptions("selectOption", options, [
15972
+ "force",
15754
15973
  "noWaitAfter",
15755
15974
  "signal",
15756
15975
  "timeout"
15757
15976
  ]);
15758
- return withAbortPrefix("locator.selectOption", () => this.ownerPage.selectOptionSelector(this.selector, values, this.label, options?.timeout, void 0, true, options?.signal));
15977
+ const force = validateForce("selectOption", options?.force);
15978
+ return withAbortPrefix("locator.selectOption", () => this.ownerPage.selectOptionSelector(this.selector, values, this.label, options?.timeout, void 0, true, options?.signal, force));
15759
15979
  }
15760
15980
  async selectText(options) {
15761
- rejectUnsupportedOptions("selectText", options, ["signal", "timeout"]);
15762
- await withAbortPrefix("locator.selectText", () => this.ownerPage.selectText(this.selector, this.label, options?.timeout, void 0, options?.signal));
15981
+ rejectUnsupportedOptions("selectText", options, [
15982
+ "force",
15983
+ "signal",
15984
+ "timeout"
15985
+ ]);
15986
+ const force = validateForce("selectText", options?.force);
15987
+ await withAbortPrefix("locator.selectText", () => this.ownerPage.selectText(this.selector, this.label, options?.timeout, void 0, options?.signal, force));
15763
15988
  }
15764
15989
  async scrollIntoViewIfNeeded(options) {
15765
15990
  rejectUnsupportedOptions("scrollIntoViewIfNeeded", options, ["signal", "timeout"]);
@@ -15793,6 +16018,10 @@ var LocatorImpl = class LocatorImpl {
15793
16018
  timeout: options.timeout
15794
16019
  }, this.label));
15795
16020
  }
16021
+ async waitForFunction(pageFunction, arg, options = {}) {
16022
+ rejectUnsupportedOptions("waitForFunction", options, ["signal", "timeout"]);
16023
+ await this.ownerPage.waitForFunctionOnSelector(this.selector, this.label, pageFunction, arg, options);
16024
+ }
15796
16025
  };
15797
16026
  /**
15798
16027
  * Single validation helper for the structured brand payload.
@@ -15805,15 +16034,6 @@ function requireBrand(value, context) {
15805
16034
  if (typeof payload !== "object" || payload === null || typeof payload.getSelector !== "function" || typeof payload.resolveElements !== "function") throw new TypeError(`${context}: expected an PlaywrightLite Locator, got incompatible branded object`);
15806
16035
  return payload;
15807
16036
  }
15808
- /** Returns the normalized `delay`, unwrapped like the pointer options. */
15809
- function rejectUnsupportedOptions(method, options, supported = []) {
15810
- if (!options) return void 0;
15811
- const unsupported = Object.keys(options).filter((key) => options[key] !== void 0 && !supported.includes(key));
15812
- if (unsupported.length > 0) throw new Error(`${method}(): unsupported Playwright option(s): ${unsupported.join(", ")}.`);
15813
- validateSignal(method, options.signal);
15814
- if (supported.includes("noWaitAfter")) validateNoWaitAfter(method, options.noWaitAfter);
15815
- return supported.includes("delay") ? validateDelay(options.delay) : void 0;
15816
- }
15817
16037
  function cssObjectToString(style) {
15818
16038
  return Object.entries(style).map(([key, value]) => {
15819
16039
  return `${key.startsWith("--") ? key : key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)}: ${value}`;
@@ -15860,6 +16080,11 @@ var PageImpl = class PageImpl {
15860
16080
  _injected;
15861
16081
  _injectedTestIdAttributeName;
15862
16082
  pointerTarget;
16083
+ /** Pinned input.ts Mouse starts at the document origin and tracks its moves. */
16084
+ pointerPosition = {
16085
+ x: 0,
16086
+ y: 0
16087
+ };
15863
16088
  defaultTimeout;
15864
16089
  defaultNavigationTimeout;
15865
16090
  constructor(browserWindow, testIdAttribute = DEFAULT_TEST_ID_ATTRIBUTE) {
@@ -15909,6 +16134,9 @@ var PageImpl = class PageImpl {
15909
16134
  elementHandleFor(element) {
15910
16135
  return element ? new AdapterElementHandle(this, element) : null;
15911
16136
  }
16137
+ previewNode(node) {
16138
+ return this.injected.previewNode(node);
16139
+ }
15912
16140
  requireSingle(selector, label) {
15913
16141
  const element = this.resolveLocatorElement(selector, true);
15914
16142
  if (!element) throw new Error(`No elements found for locator ${label}`);
@@ -15964,7 +16192,7 @@ var PageImpl = class PageImpl {
15964
16192
  return await withAbortPrefix("page.waitForSelector", () => this.waitForSelectorInRoot(this.document, selector, options));
15965
16193
  }
15966
16194
  async waitForSelectorWithinElement(root, selector, options = {}) {
15967
- return await this.waitForSelectorInRoot(root, selector, options, false);
16195
+ return await withAbortPrefix("elementHandle.waitForSelector", () => this.waitForSelectorInRoot(root, selector, options, "elementHandle.waitForSelector", false));
15968
16196
  }
15969
16197
  /**
15970
16198
  * Adapts the client Locator._expect protocol to InjectedScript.expect.
@@ -16006,7 +16234,7 @@ var PageImpl = class PageImpl {
16006
16234
  const isArray = expression === "to.have.count" || expression.endsWith(".array");
16007
16235
  const elements = this.resolveAll(selector);
16008
16236
  if (!elements.length) return missingExpectationAttempt(expression, expectOptions);
16009
- if (!isArray && elements.length > 1) throw new Error(`strict mode violation: locator ${JSON.stringify(selector)} resolved to ${elements.length} elements`);
16237
+ if (!isArray && elements.length > 1) throw presentOriginalXPath(this.injected.strictModeViolationError(this.injected.parseSelector(selector), elements), selector);
16010
16238
  const injectedOptions = Object.fromEntries(Object.entries(options).filter(([key]) => key !== "timeout" && key !== "signal"));
16011
16239
  if (expression === "to.match.aria" && typeof injectedOptions.expectedValue === "string") injectedOptions.expectedValue = parseAriaExpectation(injectedOptions.expectedValue);
16012
16240
  const result = await this.injected.expect(elements[0], {
@@ -16057,7 +16285,7 @@ var PageImpl = class PageImpl {
16057
16285
  try {
16058
16286
  if (options.modifiers) await this.keyboard.ensureModifiers(options.modifiers, deadline);
16059
16287
  this.assertActionDeadline(deadline, action);
16060
- await this.movePointer(target.point, deadline, action);
16288
+ await this.movePointer(target.point, deadline, action, options.steps);
16061
16289
  if (!options.trial && action !== "hover") await this.dispatchClick(target.element, target.point, action === "dblclick" ? 2 : options.clickCount ?? 1, options, deadline, action);
16062
16290
  } finally {
16063
16291
  interception = interceptor?.stop() ?? "done";
@@ -16092,15 +16320,21 @@ var PageImpl = class PageImpl {
16092
16320
  if (!checked && "isRadio" in state && state.isRadio) throw new Error("Cannot uncheck radio button. Radio buttons can only be unchecked by selecting another radio button in the same group.");
16093
16321
  return state.matches === checked;
16094
16322
  }
16095
- async fillSelector(selector, value, label, timeout, deadline = this.createActionDeadline(timeout), strict = true, signal) {
16323
+ async fillSelector(selector, value, label, timeout, deadline = this.createActionDeadline(timeout), strict = true, signal, apiMethod = "fill", force = false) {
16324
+ value = validateString(value, "value");
16096
16325
  this.attachActionSignal(deadline, signal);
16097
16326
  const { element } = await this.retryActionability(selector, label, "fill", [
16098
16327
  "visible",
16099
16328
  "enabled",
16100
16329
  "editable"
16101
- ], false, deadline, void 0, void 0, strict);
16330
+ ], false, deadline, void 0, void 0, strict, force);
16102
16331
  this.assertActionDeadline(deadline, "fill");
16103
- const result = this.actionableInjected.fill(element, value);
16332
+ let result;
16333
+ try {
16334
+ result = this.actionableInjected.fill(element, value);
16335
+ } catch (error) {
16336
+ throw injectedFillError(asError(error), selector, label, apiMethod, force);
16337
+ }
16104
16338
  if (result === "error:notconnected") throw new Error(`Element is not connected for locator ${label}`);
16105
16339
  if (result === "done") return;
16106
16340
  if (result !== "needsinput") throw new Error(`Unexpected fill result for locator ${label}: ${result}`);
@@ -16110,10 +16344,10 @@ var PageImpl = class PageImpl {
16110
16344
  }
16111
16345
  async pressSelector(selector, key, label, timeout, deadline = this.createActionDeadline(timeout), strict = true, signal, delay) {
16112
16346
  this.attachActionSignal(deadline, signal);
16113
- const element = await this.query(selector, label, {
16347
+ const element = typeof selector === "string" ? await this.query(selector, label, {
16114
16348
  signal,
16115
16349
  timeout
16116
- }, strict, (candidate) => candidate, deadline);
16350
+ }, strict, (candidate) => candidate, deadline) : this.resolvePointerElement(selector, label, strict);
16117
16351
  this.assertActionDeadline(deadline, "press");
16118
16352
  this.focusElement(element);
16119
16353
  await this.keyboard.press(key, { delay }, deadline);
@@ -16133,21 +16367,21 @@ var PageImpl = class PageImpl {
16133
16367
  await this.performPointerAction(selector, label, "hover", options, deadline);
16134
16368
  }
16135
16369
  async setCheckedSelector(selector, checked, label, options = {}, deadline = this.createActionDeadline(options.timeout), apiMethod = "setChecked") {
16136
- options = assertPointerActionOptions("setChecked", options);
16370
+ options = assertPointerActionOptions(apiMethod, options);
16137
16371
  if (typeof checked !== "boolean") throw new TypeError("checked must be a boolean");
16138
16372
  await this.performPointerAction(selector, label, "click", options, deadline, checked, apiMethod);
16139
16373
  }
16140
- async selectOptionSelector(selector, values, label, timeout, deadline = this.createActionDeadline(timeout), strict = true, signal) {
16374
+ async selectOptionSelector(selector, values, label, timeout, deadline = this.createActionDeadline(timeout), strict = true, signal, force = false) {
16375
+ const options = selectOptionValues(values, this.evaluation);
16141
16376
  this.attachActionSignal(deadline, signal);
16142
- const options = (values === null ? [] : Array.isArray(values) ? values : [values]).map((value) => typeof value === "string" ? { valueOrLabel: value } : value);
16143
16377
  let lastError;
16144
16378
  while (true) {
16145
16379
  if (Date.now() >= deadline.expiresAt) throw new AdapterTimeoutError(`select option: Timeout ${deadline.timeout}ms exceeded.${lastError ? ` ${lastError.message}` : ""}`, { cause: lastError });
16146
- const { element } = await this.retryActionability(selector, label, "select option", ["visible", "enabled"], false, deadline, void 0, void 0, strict);
16380
+ const { element } = await this.retryActionability(selector, label, "select option", ["visible", "enabled"], false, deadline, void 0, void 0, strict, force);
16147
16381
  this.assertActionDeadline(deadline, "select option");
16148
16382
  const result = this.actionableInjected.selectOptions(element, options);
16149
16383
  if (Array.isArray(result)) return result;
16150
- lastError = result === "error:optionnotenabled" ? /* @__PURE__ */ new Error("Element is not enabled") : result === "error:notconnected" ? /* @__PURE__ */ new Error(`Element is not connected for locator ${label}`) : /* @__PURE__ */ new Error("Options not found");
16384
+ lastError = result === "error:optionnotenabled" ? /* @__PURE__ */ new Error("option being selected is not enabled") : result === "error:notconnected" ? /* @__PURE__ */ new Error(`Element is not connected for locator ${label}`) : /* @__PURE__ */ new Error("Options not found");
16151
16385
  const remaining = deadline.expiresAt - Date.now();
16152
16386
  if (remaining <= 0) throw new AdapterTimeoutError(`select option: Timeout ${deadline.timeout}ms exceeded. ${lastError.message}`, { cause: lastError });
16153
16387
  try {
@@ -16158,15 +16392,15 @@ var PageImpl = class PageImpl {
16158
16392
  }
16159
16393
  }
16160
16394
  }
16161
- async selectText(selector, label, timeout, deadline = this.createActionDeadline(timeout), signal) {
16395
+ async selectText(selector, label, timeout, deadline = this.createActionDeadline(timeout), signal, force = false) {
16162
16396
  this.attachActionSignal(deadline, signal);
16163
- const { element } = await this.retryActionability(selector, label, "select text", ["visible"], false, deadline);
16397
+ const { element } = await this.retryActionability(selector, label, "select text", ["visible"], false, deadline, void 0, void 0, void 0, force);
16164
16398
  this.assertActionDeadline(deadline, "select text");
16165
16399
  if (this.actionableInjected.selectText(element) === "error:notconnected") throw new Error(`Element is not connected for locator ${label}`);
16166
16400
  }
16167
16401
  async scrollLocatorIntoView(selector, label, timeout, deadline = this.createActionDeadline(timeout), signal) {
16168
16402
  this.attachActionSignal(deadline, signal);
16169
- const { element } = await this.retryActionability(selector, label, "scroll into view", ["stable"], false, deadline);
16403
+ const { element } = await this.retryActionability(selector, label, "scroll into view", ["stable"], false, deadline, void 0, {});
16170
16404
  this.assertActionDeadline(deadline, "scroll into view");
16171
16405
  this.scrollIntoViewIfNeeded(element);
16172
16406
  }
@@ -16184,13 +16418,13 @@ var PageImpl = class PageImpl {
16184
16418
  throw new AdapterTimeoutError(`locator.waitFor: Timeout ${timeout}ms exceeded.\nCall log:\n - waiting for ${formatLocator(selector)} to be ${options.state}\n - Timed out waiting for ${label} to become ${options.state}.`, { cause: error });
16185
16419
  }
16186
16420
  }
16187
- async setInputFilesSelector(selector, files, options = {}, strict = false) {
16421
+ async setInputFilesSelector(selector, files, options = {}, strict = false, label = typeof selector === "string" ? selector : "elementHandle") {
16188
16422
  assertPageActionOptions("setInputFiles", options, ["noWaitAfter", "strict"]);
16189
16423
  if (options.strict !== void 0 && typeof options.strict !== "boolean") throw new TypeError("setInputFiles strict must be a boolean");
16190
16424
  const payloads = inputFilePayloads(files);
16191
16425
  const deadline = this.createActionDeadline(options.timeout);
16192
16426
  this.attachActionSignal(deadline, options.signal);
16193
- await this.query(selector, selector, {
16427
+ await this.query(selector, label, {
16194
16428
  signal: options.signal,
16195
16429
  timeout: options.timeout
16196
16430
  }, strict || options.strict === true, (element) => {
@@ -16205,6 +16439,148 @@ var PageImpl = class PageImpl {
16205
16439
  }, deadline);
16206
16440
  }
16207
16441
  /**
16442
+ * Simulates an external drag-and-drop onto the resolved element.
16443
+ *
16444
+ * Mirrors pinned 26a9e47 `server/dom.ts` ElementHandle._drop: the element is
16445
+ * awaited visible and stable (never enabled), then one synthetic
16446
+ * `DataTransfer` carries the payload through `dragenter`, `dragover` and
16447
+ * `drop` at the action point. A `dragover` handler that does not call
16448
+ * `preventDefault()` rejects the drop, which ends with `dragleave`.
16449
+ */
16450
+ async dropSelector(selector, label, payload, options = {}, strict = true) {
16451
+ assertPageActionOptions("drop", options, ["position"]);
16452
+ const files = payload?.files === void 0 ? [] : inputFilePayloads(payload.files, "drop");
16453
+ const data = Object.entries(payload?.data ?? {});
16454
+ if (files.length === 0 && data.length === 0) throw new Error("At least one of \"files\" or \"data\" must be provided.");
16455
+ const deadline = this.createActionDeadline(options.timeout);
16456
+ this.attachActionSignal(deadline, options.signal);
16457
+ const { element, point } = await this.retryActionability(selector, label, "drop", ["visible", "stable"], true, deadline, options.position, {
16458
+ ...options,
16459
+ strict
16460
+ });
16461
+ this.assertActionDeadline(deadline, "drop");
16462
+ this.dispatchDrop(element, point, files, data);
16463
+ }
16464
+ /** The page function of pinned `server/dom.ts` ElementHandle._drop. */
16465
+ dispatchDrop(element, point, files, data) {
16466
+ const transfer = new this.window.DataTransfer();
16467
+ for (const file of files) {
16468
+ const bytes = Uint8Array.from(this.window.atob(file.buffer), (character) => character.charCodeAt(0));
16469
+ transfer.items.add(new this.window.File([bytes], file.name, { type: file.mimeType }));
16470
+ }
16471
+ for (const [mimeType, value] of data) transfer.setData(mimeType, value);
16472
+ const dragEvent = (type) => new this.window.DragEvent(type, {
16473
+ bubbles: true,
16474
+ cancelable: true,
16475
+ composed: true,
16476
+ clientX: point.x,
16477
+ clientY: point.y,
16478
+ dataTransfer: transfer
16479
+ });
16480
+ element.dispatchEvent(dragEvent("dragenter"));
16481
+ const over = dragEvent("dragover");
16482
+ element.dispatchEvent(over);
16483
+ if (!over.defaultPrevented) {
16484
+ element.dispatchEvent(dragEvent("dragleave"));
16485
+ throw new Error("Drop target did not accept the drop — its dragover handler did not call preventDefault()");
16486
+ }
16487
+ element.dispatchEvent(dragEvent("drop"));
16488
+ }
16489
+ /**
16490
+ * Adds a `<script>` tag to the controlled document.
16491
+ *
16492
+ * Mirrors pinned 26a9e47 `server/frames.ts` Frame._addScriptTag and its
16493
+ * `addScriptUrl`/`addScriptContent` page functions: a `url` script resolves
16494
+ * on its load event and fails naming the source, while `content` is injected
16495
+ * as `text/javascript` unless `type` says otherwise.
16496
+ */
16497
+ async addScriptTag(options = {}) {
16498
+ const { url = null, content = null, type = "" } = assertAddTagOptions("addScriptTag", options);
16499
+ return await this.raceWithCSPError(async () => {
16500
+ const script = this.document.createElement("script");
16501
+ if (url !== null) {
16502
+ script.src = url;
16503
+ if (type) script.type = type;
16504
+ await this.appendLoadedTag(script, () => `Failed to load script at ${script.src}`);
16505
+ return this.elementHandleFor(script);
16506
+ }
16507
+ script.type = type || "text/javascript";
16508
+ script.text = content;
16509
+ let error = null;
16510
+ script.onerror = (event) => error = event;
16511
+ this.document.head.appendChild(script);
16512
+ if (error) throw error;
16513
+ await new Promise((resolve) => this.window.setTimeout(resolve));
16514
+ return this.elementHandleFor(script);
16515
+ });
16516
+ }
16517
+ /**
16518
+ * Adds a `<link rel="stylesheet">` or `<style type="text/css">` tag to the
16519
+ * controlled document.
16520
+ *
16521
+ * Mirrors pinned 26a9e47 `server/frames.ts` Frame._addStyleTag and its
16522
+ * `addStyleUrl`/`addStyleContent` page functions, which resolve on the load
16523
+ * event of the inserted tag. The pinned page functions reject with the raw
16524
+ * error event; this names the stylesheet instead, as the pinned script tag
16525
+ * does.
16526
+ */
16527
+ async addStyleTag(options = {}) {
16528
+ const { url = null, content = null } = assertAddTagOptions("addStyleTag", options);
16529
+ return await this.raceWithCSPError(async () => {
16530
+ if (url !== null) {
16531
+ const link = this.document.createElement("link");
16532
+ link.rel = "stylesheet";
16533
+ link.href = url;
16534
+ await this.appendLoadedTag(link, () => `Failed to load style at ${link.href}`);
16535
+ return this.elementHandleFor(link);
16536
+ }
16537
+ const style = this.document.createElement("style");
16538
+ style.type = "text/css";
16539
+ style.appendChild(this.document.createTextNode(content));
16540
+ await this.appendLoadedTag(style, () => "Failed to apply the injected style content");
16541
+ return this.elementHandleFor(style);
16542
+ });
16543
+ }
16544
+ /** Appends a tag to the document head and settles on its load event. */
16545
+ appendLoadedTag(tag, failure) {
16546
+ const loaded = new Promise((resolve, reject) => {
16547
+ tag.onload = () => resolve();
16548
+ tag.onerror = () => reject(new Error(failure()));
16549
+ });
16550
+ this.document.head.appendChild(tag);
16551
+ return loaded;
16552
+ }
16553
+ /**
16554
+ * Fails a tag insertion the document's Content Security Policy blocked.
16555
+ *
16556
+ * Mirrors pinned 26a9e47 `server/frames.ts` Frame._raceWithCSPError, which
16557
+ * races the insertion against the browser's CSP report. That report reaches
16558
+ * the pinned code as a console message; inside the document the browser
16559
+ * reports the same violation as a `securitypolicyviolation` event.
16560
+ */
16561
+ async raceWithCSPError(action) {
16562
+ let violation;
16563
+ let onViolation = () => {};
16564
+ const violated = new Promise((resolve) => {
16565
+ onViolation = (event) => {
16566
+ violation = event;
16567
+ resolve();
16568
+ };
16569
+ });
16570
+ this.document.addEventListener("securitypolicyviolation", onViolation);
16571
+ let result;
16572
+ let error;
16573
+ const completed = action().then((value) => void (result = value), (reason) => void (error = reason));
16574
+ try {
16575
+ await Promise.race([completed, violated]);
16576
+ } finally {
16577
+ this.document.removeEventListener("securitypolicyviolation", onViolation);
16578
+ }
16579
+ if (violation) throw new Error(`Content Security Policy directive "${violation.violatedDirective}" blocked ${violation.blockedURI || "an inline resource"}`);
16580
+ if (error) throw error;
16581
+ return result;
16582
+ }
16583
+ /**
16208
16584
  * Serializes the controlled document.
16209
16585
  *
16210
16586
  * Mirrors pinned 26a9e47 `server/frames.ts` Frame._content: serialize the
@@ -16268,8 +16644,13 @@ var PageImpl = class PageImpl {
16268
16644
  });
16269
16645
  }
16270
16646
  async fill(selector, value, options) {
16271
- assertPageActionOptions("fill", options, ["noWaitAfter", "strict"]);
16272
- await withAbortPrefix("page.fill", () => this.fillSelector(selector, value, `page.fill(${JSON.stringify(selector)})`, options?.timeout, void 0, options?.strict === true, options?.signal));
16647
+ assertPageActionOptions("fill", options, [
16648
+ "force",
16649
+ "noWaitAfter",
16650
+ "strict"
16651
+ ]);
16652
+ const force = validateForce("fill", options?.force);
16653
+ await withAbortPrefix("page.fill", () => this.fillSelector(selector, value, `page.fill(${JSON.stringify(selector)})`, options?.timeout, void 0, options?.strict === true, options?.signal, "fill", force));
16273
16654
  }
16274
16655
  async setInputFiles(selector, files, options) {
16275
16656
  await withAbortPrefix("page.setInputFiles", () => this.setInputFilesSelector(selector, files, options));
@@ -16315,20 +16696,25 @@ var PageImpl = class PageImpl {
16315
16696
  });
16316
16697
  }
16317
16698
  async selectOption(selector, values, options) {
16318
- assertPageActionOptions("selectOption", options, ["noWaitAfter", "strict"]);
16319
- return withAbortPrefix("page.selectOption", () => this.selectOptionSelector(selector, values, `page.selectOption(${JSON.stringify(selector)})`, options?.timeout, void 0, options?.strict === true, options?.signal));
16699
+ assertPageActionOptions("selectOption", options, [
16700
+ "force",
16701
+ "noWaitAfter",
16702
+ "strict"
16703
+ ]);
16704
+ const force = validateForce("selectOption", options?.force);
16705
+ return withAbortPrefix("page.selectOption", () => this.selectOptionSelector(selector, values, `page.selectOption(${JSON.stringify(selector)})`, options?.timeout, void 0, options?.strict === true, options?.signal, force));
16320
16706
  }
16321
16707
  async check(selector, options) {
16322
16708
  await this.setCheckedSelector(selector, true, `page.check(${JSON.stringify(selector)})`, {
16323
16709
  ...options,
16324
16710
  strict: options?.strict ?? false
16325
- });
16711
+ }, void 0, "check");
16326
16712
  }
16327
16713
  async uncheck(selector, options) {
16328
16714
  await this.setCheckedSelector(selector, false, `page.uncheck(${JSON.stringify(selector)})`, {
16329
16715
  ...options,
16330
16716
  strict: options?.strict ?? false
16331
- });
16717
+ }, void 0, "uncheck");
16332
16718
  }
16333
16719
  async setChecked(selector, checked, options) {
16334
16720
  await this.setCheckedSelector(selector, checked, `page.setChecked(${JSON.stringify(selector)})`, {
@@ -16348,10 +16734,11 @@ var PageImpl = class PageImpl {
16348
16734
  }
16349
16735
  async dispatchEventSelector(selector, type, eventInit, label, timeout, deadline = this.createActionDeadline(timeout), strict = true, signal) {
16350
16736
  this.attachActionSignal(deadline, signal);
16737
+ const init = this.evaluation.unwrapHandles(eventInit);
16351
16738
  await this.query(selector, label, {
16352
16739
  signal,
16353
16740
  timeout
16354
- }, strict, (element) => this.actionableInjected.dispatchEvent(element, type, eventInit), deadline);
16741
+ }, strict, (element) => this.actionableInjected.dispatchEvent(element, type, init), deadline);
16355
16742
  }
16356
16743
  /**
16357
16744
  * Pinned 26a9e47 client/frame.ts and server/frames.ts default to load,
@@ -16364,15 +16751,16 @@ var PageImpl = class PageImpl {
16364
16751
  */
16365
16752
  async goto(url, options = {}) {
16366
16753
  for (const [key, value] of Object.entries(options)) if (!["timeout", "waitUntil"].includes(key) && value !== void 0) throw new Error(`Unsupported Playwright option: goto.${key}`);
16367
- const waitUntil = options.waitUntil ?? "load";
16368
- if (![
16369
- "commit",
16370
- "domcontentloaded",
16371
- "load"
16372
- ].includes(waitUntil)) throw new Error(`Unsupported waitUntil value: ${waitUntil}`);
16754
+ const waitUntil = verifyLoadState("waitUntil", options.waitUntil === void 0 ? "load" : options.waitUntil);
16755
+ if (waitUntil === "networkidle") throw new Error(`Unsupported waitUntil value: ${waitUntil}`);
16373
16756
  const timeout = this.resolveTimeout(options.timeout, DEFAULT_NAVIGATION_TIMEOUT, true);
16374
16757
  if (typeof url !== "string") throw new Error("goto URL must be a string");
16375
- const target = new URL(url, this.document.baseURI);
16758
+ let target;
16759
+ try {
16760
+ target = new URL(url, this.document.baseURI);
16761
+ } catch {
16762
+ throw new Error("page.goto: Cannot navigate to invalid URL");
16763
+ }
16376
16764
  if (![
16377
16765
  "http:",
16378
16766
  "https:",
@@ -16459,6 +16847,12 @@ var PageImpl = class PageImpl {
16459
16847
  assertEvaluationOptions(options);
16460
16848
  return this._evaluateExpression(pageFunction, typeof pageFunction === "function", arg);
16461
16849
  }
16850
+ /** Keeps the result in the document, referenced by a handle. */
16851
+ async evaluateHandle(pageFunction, arg, options) {
16852
+ assertMaxArguments(arguments.length, 3);
16853
+ assertEvaluationOptions(options);
16854
+ return this.evaluation.byHandle(pageFunction, typeof pageFunction === "function", arg);
16855
+ }
16462
16856
  /** Evaluates through the pinned Playwright UtilityScript. */
16463
16857
  async $eval(selector, callback, arg) {
16464
16858
  assertMaxArguments(arguments.length, 3);
@@ -16482,28 +16876,39 @@ var PageImpl = class PageImpl {
16482
16876
  }
16483
16877
  /**
16484
16878
  * Polls a predicate in the controlled document until it returns a
16485
- * truthy value.
16486
- *
16487
- * Mirrors pinned 26a9e47 server/frames.ts:1626-1694:
16488
- * - pollingInterval must be >0 (frames.ts:1628)
16489
- * - expression is normalized (frames.ts:1629)
16490
- * - isFunction=true → eval once, call each poll (frames.ts:1640-1642)
16491
- * - isFunction=false → re-eval each poll (frames.ts:1643-1644,
16492
- * since evaledExpression is never cached)
16493
- * - abort mechanism cleans up pending timers (frames.ts:1679-1681)
16494
- * - timeout races independently (handles never-settling predicates)
16879
+ * truthy value. Public API: derives isFunction from typeof pageFunction.
16495
16880
  *
16496
16881
  * Returns a minimal handle with `jsonValue()` and `dispose()`,
16497
16882
  * mirroring pinned client JSHandle interface.
16498
16883
  */
16499
- /**
16500
- * Public API: derives isFunction from typeof pageFunction.
16501
- */
16502
16884
  async waitForFunction(pageFunction, arg, options) {
16503
16885
  return this._waitForFunctionExpression(typeof pageFunction === "function" ? pageFunction : String(pageFunction), typeof pageFunction === "function", arg, options);
16504
16886
  }
16505
16887
  /**
16506
16888
  * Internal: accepts explicit isFunction for bridge transport.
16889
+ */
16890
+ async _waitForFunctionExpression(pageFunction, isFunction, arg, options) {
16891
+ const value = await this.pollPredicate("page.waitForFunction", pageFunction, isFunction, arg, options);
16892
+ return this.evaluation.handleFor(value);
16893
+ }
16894
+ /**
16895
+ * The `Locator` form of the member. Mirrors pinned 26a9e47
16896
+ * server/frames.ts:1696-1712 `waitForFunctionExpressionOnElement`: the
16897
+ * selector is re-resolved strictly on every poll and its element is passed
16898
+ * to the predicate ahead of `arg`, so a re-rendered element is tolerated.
16899
+ * The pinned client discards the predicate's value (`client/locator.ts`
16900
+ * `waitForFunction` awaits the channel call and returns nothing), and it
16901
+ * sends neither `polling` nor a handle back.
16902
+ */
16903
+ async waitForFunctionOnSelector(selector, label, pageFunction, arg, options) {
16904
+ await this.pollPredicate("locator.waitForFunction", pageFunction, typeof pageFunction === "function", arg, options, {
16905
+ selector,
16906
+ label
16907
+ });
16908
+ }
16909
+ /**
16910
+ * Shared polling engine of both forms. Resolves with the first truthy
16911
+ * predicate value.
16507
16912
  *
16508
16913
  * Mirrors pinned 26a9e47 server/frames.ts:1626-1694:
16509
16914
  * - pollingInterval must be >0 (frames.ts:1628)
@@ -16513,38 +16918,66 @@ var PageImpl = class PageImpl {
16513
16918
  * since evaledExpression is never cached)
16514
16919
  * - abort mechanism cleans up pending timers (frames.ts:1679-1681)
16515
16920
  * - timeout races independently (handles never-settling predicates)
16921
+ *
16922
+ * `target` names the locator of the element form: it is re-resolved
16923
+ * strictly on every poll, so a locator that matches nothing yet keeps
16924
+ * polling while a strict mode violation ends the wait.
16516
16925
  */
16517
- async _waitForFunctionExpression(pageFunction, isFunction, arg, options) {
16926
+ async pollPredicate(apiName, pageFunction, isFunction, arg, options, target) {
16518
16927
  const timeout = this.resolveTimeout(options?.timeout, 3e4);
16928
+ validateSignal("waitForFunction", options?.signal);
16929
+ const signal = options?.signal;
16519
16930
  const predicate = this.evaluation.predicate(pageFunction, isFunction, arg);
16520
16931
  const polling = options?.polling ?? "raf";
16521
16932
  if (typeof polling === "string" && polling !== "raf") throw new Error("Unknown polling option: " + polling);
16522
16933
  if (typeof polling === "number" && polling <= 0) throw new Error("Cannot poll with non-positive interval: " + polling);
16523
- return new Promise((resolve, reject) => {
16934
+ return withAbortPrefix(apiName, () => new Promise((resolve, reject) => {
16524
16935
  let aborted = false;
16525
16936
  let timeoutId;
16526
16937
  let pollTimerId;
16527
16938
  let rafId;
16939
+ if (signal?.aborted) {
16940
+ reject(actionAborted(signal, false));
16941
+ return;
16942
+ }
16528
16943
  if (timeout > 0) timeoutId = this.window.setTimeout(() => {
16529
16944
  cleanup();
16530
- reject(new AdapterTimeoutError(`page.waitForFunction: Timeout ${timeout}ms exceeded.`));
16945
+ reject(new AdapterTimeoutError(`${apiName}: Timeout ${timeout}ms exceeded.` + (target ? queryCallLog(target.selector) : "")));
16531
16946
  }, timeout);
16532
16947
  const cleanup = () => {
16533
16948
  aborted = true;
16949
+ signal?.removeEventListener("abort", onAbort);
16534
16950
  if (timeoutId !== void 0) this.window.clearTimeout(timeoutId);
16535
16951
  if (pollTimerId !== void 0) this.window.clearTimeout(pollTimerId);
16536
16952
  if (rafId !== void 0) this.window.cancelAnimationFrame(rafId);
16537
16953
  };
16954
+ const onAbort = () => {
16955
+ cleanup();
16956
+ reject(actionAborted(signal, true));
16957
+ };
16958
+ signal?.addEventListener("abort", onAbort, { once: true });
16538
16959
  const check = () => {
16539
16960
  if (aborted) return;
16961
+ let element;
16962
+ if (target) try {
16963
+ element = this.queryElement(target.selector, target.label, true);
16964
+ } catch (e) {
16965
+ if (!isRetryableQueryError(e)) {
16966
+ cleanup();
16967
+ reject(e);
16968
+ return;
16969
+ }
16970
+ scheduleNext();
16971
+ return;
16972
+ }
16540
16973
  try {
16541
- const result = predicate();
16974
+ const result = predicate(element);
16542
16975
  if (result && typeof result?.then === "function") {
16543
16976
  result.then((v) => {
16544
16977
  if (aborted) return;
16545
16978
  if (v) {
16546
16979
  cleanup();
16547
- resolve(new AdapterJSHandle(v, this.evaluation));
16980
+ resolve(v);
16548
16981
  } else scheduleNext();
16549
16982
  }, (e) => {
16550
16983
  if (aborted) return;
@@ -16555,7 +16988,7 @@ var PageImpl = class PageImpl {
16555
16988
  }
16556
16989
  if (result) {
16557
16990
  cleanup();
16558
- resolve(new AdapterJSHandle(result, this.evaluation));
16991
+ resolve(result);
16559
16992
  return;
16560
16993
  }
16561
16994
  } catch (e) {
@@ -16571,7 +17004,7 @@ var PageImpl = class PageImpl {
16571
17004
  else pollTimerId = this.window.setTimeout(check, polling);
16572
17005
  };
16573
17006
  check();
16574
- });
17007
+ }));
16575
17008
  }
16576
17009
  getByRole(role, options = {}) {
16577
17010
  const roleSelector = getByRoleSelector(role, options);
@@ -16692,10 +17125,16 @@ var PageImpl = class PageImpl {
16692
17125
  }, true, (element) => this.injectedAriaSnapshot(element, options));
16693
17126
  }
16694
17127
  async locatorEvaluate(selector, label, pageFunction, arg, options) {
17128
+ return this.evaluation.byValue(pageFunction, typeof pageFunction === "function", arg, await this.locatorEvaluationTarget(selector, label, options));
17129
+ }
17130
+ async locatorEvaluateHandle(selector, label, pageFunction, arg, options) {
17131
+ return this.evaluation.byHandle(pageFunction, typeof pageFunction === "function", arg, await this.locatorEvaluationTarget(selector, label, options));
17132
+ }
17133
+ /** Pinned locator.ts resolves the element before it evaluates against it. */
17134
+ async locatorEvaluationTarget(selector, label, options) {
16695
17135
  assertEvaluationOptions(options);
16696
17136
  const { exposeFunctions: _exposeFunctions, ...queryOptions } = options ?? {};
16697
- const element = await this.query(selector, label, queryOptions, true, (element) => element);
16698
- return this.evaluation.byValue(pageFunction, typeof pageFunction === "function", arg, element);
17137
+ return this.query(selector, label, queryOptions, true, (element) => element);
16699
17138
  }
16700
17139
  async queryState(selector, state, options, strict, label = `page.is${state[0].toUpperCase()}${state.slice(1)}(${JSON.stringify(selector)})`) {
16701
17140
  return this.query(selector, label, options, strict, (element) => {
@@ -16728,6 +17167,7 @@ var PageImpl = class PageImpl {
16728
17167
  async waitForElementState(element, state, options = {}) {
16729
17168
  assertElementHandleStateOptions(state, options);
16730
17169
  const deadline = this.createActionDeadline(options.timeout);
17170
+ this.attachActionSignal(deadline, options.signal);
16731
17171
  const timeoutError = () => new AdapterTimeoutError(`elementHandle.waitForElementState: Timeout ${deadline.timeout}ms exceeded.`);
16732
17172
  while (true) {
16733
17173
  if (deadline.expiresAt !== Infinity && Date.now() >= deadline.expiresAt) throw timeoutError();
@@ -16736,7 +17176,7 @@ var PageImpl = class PageImpl {
16736
17176
  await this.wait(deadline.expiresAt === Infinity ? 10 : Math.min(10, deadline.expiresAt - Date.now()));
16737
17177
  }
16738
17178
  }
16739
- async waitForSelectorInRoot(root, selector, options, allowsStrict = true) {
17179
+ async waitForSelectorInRoot(root, selector, options, apiName = "page.waitForSelector", allowsStrict = true) {
16740
17180
  assertWaitForSelectorOptions(options, allowsStrict);
16741
17181
  const state = options.state ?? "visible";
16742
17182
  const timeout = this.resolveTimeout(options.timeout, DEFAULT_ACTION_TIMEOUT);
@@ -16748,7 +17188,7 @@ var PageImpl = class PageImpl {
16748
17188
  const visible = !!element && this.elementState(element, "visible").matches === true;
16749
17189
  if (state === "attached" && element || state === "visible" && visible) return this.elementHandleFor(element);
16750
17190
  if (state === "detached" && !element || state === "hidden" && !visible) return null;
16751
- if (Date.now() >= deadline) throw new AdapterTimeoutError(`page.waitForSelector: Timeout ${timeout}ms exceeded.\nCall log:\n - waiting for ${formatLocator(selector)} to be ${state}`);
17191
+ if (Date.now() >= deadline) throw new AdapterTimeoutError(`${apiName}: Timeout ${timeout}ms exceeded.\nCall log:\n - waiting for ${formatLocator(selector)} to be ${state}`);
16752
17192
  const delay = Math.min(QUERY_RETRY_DELAY, deadline - Date.now());
16753
17193
  if (!await waitForExpectationRetry(this.window, delay, signal)) throw actionAborted(signal, true);
16754
17194
  }
@@ -16777,11 +17217,11 @@ var PageImpl = class PageImpl {
16777
17217
  if (signal?.aborted) throw actionAborted(signal, false);
16778
17218
  const deadline = actionDeadline?.expiresAt ?? (timeout === 0 ? Infinity : Date.now() + timeout);
16779
17219
  while (true) try {
16780
- return await evaluate(this.queryElement(selector, label, strict || options?.strict === true));
17220
+ return await evaluate(this.resolvePointerElement(selector, label, strict || options?.strict === true));
16781
17221
  } catch (error) {
16782
17222
  if (!isRetryableQueryError(error)) throw error;
16783
17223
  const remaining = deadline - Date.now();
16784
- if (remaining <= 0) throw new AdapterTimeoutError(`Timeout ${timeout}ms exceeded.\nCall log:\n - waiting for ${formatLocator(selector)}`, { cause: error });
17224
+ if (remaining <= 0) throw new AdapterTimeoutError(`Timeout ${timeout}ms exceeded.${queryCallLog(selector)}`, { cause: error });
16785
17225
  const delay = Math.min(QUERY_RETRY_DELAY, remaining);
16786
17226
  if (!await waitForExpectationRetry(this.window, delay, signal)) throw actionAborted(signal, true);
16787
17227
  }
@@ -16837,7 +17277,7 @@ var PageImpl = class PageImpl {
16837
17277
  }
16838
17278
  return /* @__PURE__ */ new Error("Element is not stable");
16839
17279
  }
16840
- async retryActionability(selector, label, actionName, states, checkHitTarget, deadline, position, pointerOptions, strict = pointerOptions?.strict ?? true) {
17280
+ async retryActionability(selector, label, actionName, states, checkHitTarget, deadline, position, pointerOptions, strict = pointerOptions?.strict ?? true, force = pointerOptions?.force ?? false) {
16841
17281
  let lastError;
16842
17282
  let retry = 0;
16843
17283
  const log = [];
@@ -16850,10 +17290,12 @@ var PageImpl = class PageImpl {
16850
17290
  if (Date.now() >= deadline.expiresAt) throwTimeout();
16851
17291
  try {
16852
17292
  const element = this.resolvePointerElement(selector, label, strict);
16853
- if (pointerOptions && !pointerOptions.force) log.push(` - waiting for element to be ${states.includes("enabled") ? "visible, enabled and stable" : "visible and stable"}`);
16854
- if (!pointerOptions?.force) await this.ensureActionable(element, states, deadline);
17293
+ if (pointerOptions && !force) log.push(` - waiting for element to be ${states.includes("enabled") ? "visible, enabled and stable" : "visible and stable"}`);
17294
+ if (!force) await this.ensureActionable(element, states, deadline);
16855
17295
  if (Date.now() >= deadline.expiresAt) throwTimeout();
16856
- if (actionName !== "scroll into view" && pointerOptions?.scroll !== "none") {
17296
+ if (actionName === "scroll into view") {
17297
+ if (!this.hasLayoutBox(element)) throw new Error("Element is not visible");
17298
+ } else if (pointerOptions?.scroll !== "none") {
16857
17299
  if (!pointerOptions || position) this.scrollIntoView(element, position);
16858
17300
  else if (retry % 4 === 0) this.scrollIntoViewIfNeeded(element);
16859
17301
  else element.scrollIntoView({
@@ -16870,8 +17312,8 @@ var PageImpl = class PageImpl {
16870
17312
  behavior: "instant"
16871
17313
  });
16872
17314
  }
16873
- if (!pointerOptions?.force) await this.ensureActionable(element, states, deadline);
16874
- const point = checkHitTarget ? this.ensureReceivesEvents(element, position, !!pointerOptions?.force) : actionPoint(element, position, this.window);
17315
+ if (!force) await this.ensureActionable(element, states, deadline);
17316
+ const point = checkHitTarget ? this.ensureReceivesEvents(element, position, force) : actionPoint(element, position, this.window);
16875
17317
  if (Date.now() >= deadline.expiresAt) throwTimeout();
16876
17318
  return {
16877
17319
  element,
@@ -16879,7 +17321,7 @@ var PageImpl = class PageImpl {
16879
17321
  };
16880
17322
  } catch (error) {
16881
17323
  if (typeof selector !== "string" && !selector.isConnected) throw new Error("Element is not attached to the DOM", { cause: error });
16882
- if (!isRetryableActionError(error) || pointerOptions?.force && !asError(error).message.startsWith("No elements found for locator")) throw error;
17324
+ if (!isRetryableActionError(error) || force && !asError(error).message.startsWith("No elements found for locator")) throw error;
16883
17325
  lastError = asError(error);
16884
17326
  const remaining = deadline.expiresAt - Date.now();
16885
17327
  const delay = pointerOptions ? [
@@ -16905,6 +17347,17 @@ var PageImpl = class PageImpl {
16905
17347
  }
16906
17348
  }
16907
17349
  }
17350
+ /**
17351
+ * Whether the element is rendered at all. `display: contents` has no box of
17352
+ * its own, so its contents answer for it, exactly as the scroll below does.
17353
+ */
17354
+ hasLayoutBox(element) {
17355
+ if (element.getClientRects().length > 0) return true;
17356
+ if (this.window.getComputedStyle(element).display !== "contents") return false;
17357
+ const range = this.document.createRange();
17358
+ range.selectNodeContents(element);
17359
+ return range.getClientRects().length > 0;
17360
+ }
16908
17361
  scrollIntoView(element, position) {
16909
17362
  if (typeof element.scrollIntoView !== "function") return;
16910
17363
  element.scrollIntoView({
@@ -17005,7 +17458,20 @@ var PageImpl = class PageImpl {
17005
17458
  }
17006
17459
  }));
17007
17460
  }
17008
- async movePointer(point, deadline, action) {
17461
+ /**
17462
+ * Mirrors pinned input.ts Mouse.move: `steps` interpolated positions between
17463
+ * the pointer's previous location and `point`, the last landing exactly on
17464
+ * it. `steps` defaults to 1, a single move to the destination.
17465
+ */
17466
+ async movePointer(point, deadline, action, steps = 1) {
17467
+ const from = this.pointerPosition;
17468
+ this.pointerPosition = point;
17469
+ for (let step = 1; step <= steps; step++) await this.movePointerTo({
17470
+ x: from.x + (point.x - from.x) * (step / steps),
17471
+ y: from.y + (point.y - from.y) * (step / steps)
17472
+ }, deadline, action);
17473
+ }
17474
+ async movePointerTo(point, deadline, action) {
17009
17475
  const target = this.eventTargetAtPoint(point);
17010
17476
  const previous = this.pointerTarget;
17011
17477
  if (previous !== target && previous?.isConnected) {
@@ -17080,6 +17546,7 @@ var PageImpl = class PageImpl {
17080
17546
  insertPressedText(element, text, inputType = "insertText", eventData = text, deadline) {
17081
17547
  this.assertActionDeadline(deadline, "press");
17082
17548
  if (!isEditableElement(element, this.window)) return;
17549
+ if (this.insertTextAtCaret(element, text, inputType)) return;
17083
17550
  if (isFillableInputWithoutSelection(element, this.window)) {
17084
17551
  element.value += text;
17085
17552
  this.dispatchInputEvent(element, eventData, inputType);
@@ -17087,10 +17554,30 @@ var PageImpl = class PageImpl {
17087
17554
  }
17088
17555
  this.replaceSelectedText(element, text, inputType, eventData);
17089
17556
  }
17090
- insertKeyboardText(element, text, inputType = "insertText", eventData = text, deadline) {
17557
+ /**
17558
+ * Inserts text at the caret the browser itself keeps, dispatching its own
17559
+ * input event. Playwright types through the browser's editing engine; the
17560
+ * pinned in-document input emulation reaches for this editing command for
17561
+ * the same reason (coreBundle `_insertText`). It is the only script
17562
+ * primitive that finds the caret in an input type that exposes no selection
17563
+ * API, and in an editable host inside a shadow root, whose selection the
17564
+ * document reports retargeted to the host.
17565
+ */
17566
+ insertTextAtCaret(element, text, inputType) {
17567
+ if (inputType !== "insertText") return false;
17568
+ if (this.deepActiveElement() !== element) return false;
17569
+ return this.document.execCommand("insertText", false, text);
17570
+ }
17571
+ deepActiveElement() {
17572
+ let target = this.document.activeElement ?? this.document.body;
17573
+ while (target.shadowRoot?.mode === "open" && target.shadowRoot.activeElement) target = target.shadowRoot.activeElement;
17574
+ return target;
17575
+ }
17576
+ insertKeyboardText(element, text, inputType = "insertText", eventData = text, deadline, typedByKey = false) {
17091
17577
  this.assertActionDeadline(deadline, "press");
17092
17578
  if (!isEditableElement(element, this.window)) return;
17093
17579
  if (!this.dispatchBeforeInput(element, eventData, inputType)) return;
17580
+ if (typedByKey && !this.dispatchTextInput(element, text)) return;
17094
17581
  this.assertActionDeadline(deadline, "press");
17095
17582
  this.insertPressedText(element, text, inputType, eventData, deadline);
17096
17583
  }
@@ -17171,6 +17658,11 @@ var PageImpl = class PageImpl {
17171
17658
  inputType
17172
17659
  }));
17173
17660
  }
17661
+ dispatchTextInput(element, text) {
17662
+ const event = this.document.createEvent("TextEvent");
17663
+ event.initTextEvent("textInput", true, true, this.window, text);
17664
+ return element.dispatchEvent(event);
17665
+ }
17174
17666
  dispatchInputEvent(element, data = null, inputType = "insertText") {
17175
17667
  const InputEvent = this.window.InputEvent;
17176
17668
  element.dispatchEvent(InputEvent ? new InputEvent("input", {
@@ -17402,7 +17894,7 @@ var BrowserKeyboard = class {
17402
17894
  if (dispatchKeyPress) await this.waitForKeyboardPhase(deadline);
17403
17895
  if (keyPressAllowed && description.text && description.key !== "Enter") {
17404
17896
  this.page.checkKeyboardActionDeadline(deadline);
17405
- this.page.insertKeyboardText(this.activeTarget(), description.text, "insertText", description.text, deadline);
17897
+ this.page.insertKeyboardText(this.activeTarget(), description.text, "insertText", description.text, deadline, true);
17406
17898
  }
17407
17899
  if (keyPressAllowed && description.key === "Enter") {
17408
17900
  this.page.checkKeyboardActionDeadline(deadline);
@@ -17422,9 +17914,7 @@ var BrowserKeyboard = class {
17422
17914
  if (keyDownState?.allowed && keyUpAllowed && keyUpTarget === keyDownState.target && this.activeTarget() === keyDownState.target) this.page.applyKeyupDefault(keyDownState.target, description, this.pressedModifiers);
17423
17915
  }
17424
17916
  activeTarget() {
17425
- let target = this.page.document.activeElement ?? this.page.document.body;
17426
- while (target.shadowRoot?.mode === "open" && target.shadowRoot.activeElement) target = target.shadowRoot.activeElement;
17427
- return target;
17917
+ return this.page.deepActiveElement();
17428
17918
  }
17429
17919
  descriptionFor(key) {
17430
17920
  const resolved = resolveKeyboardKey(key, this.page.window);
@@ -17553,6 +18043,17 @@ function validateTimeout(timeout, name) {
17553
18043
  if (typeof timeout !== "number" || timeout < 0 || !Number.isFinite(timeout)) throw new TypeError(`${name} must be a non-negative finite number`);
17554
18044
  return timeout;
17555
18045
  }
18046
+ /**
18047
+ * Options of `addScriptTag` and `addStyleTag`. The pinned client reads `path`
18048
+ * from disk into `content` before the call leaves the process, which this
18049
+ * runtime cannot do; every other shape reaches the pinned server check for a
18050
+ * `url` or `content` property unexamined, including a non-object argument.
18051
+ */
18052
+ function assertAddTagOptions(method, options) {
18053
+ if (options?.path !== void 0) throw new Error(`${method}: the \`path\` option is not supported; pass \`url\` or \`content\`.`);
18054
+ if (!options?.url && !options?.content) throw new Error("Provide an object with a `url`, `path` or `content` property");
18055
+ return options;
18056
+ }
17556
18057
  /** Returns the normalized `delay`, unwrapped like the pointer options. */
17557
18058
  function assertPageActionOptions(method, options, supported = []) {
17558
18059
  if (!options) return void 0;
@@ -17579,7 +18080,7 @@ function assertPointerActionOptions(method, options) {
17579
18080
  "scroll",
17580
18081
  "strict"
17581
18082
  ];
17582
- if (method === "click" || method === "dblclick") supported.push("button", "delay", "modifiers");
18083
+ if (method === "click" || method === "dblclick") supported.push("button", "delay", "modifiers", "steps");
17583
18084
  if (method === "click") supported.push("clickCount");
17584
18085
  if (method === "hover") supported.push("modifiers");
17585
18086
  if (!options) return {};
@@ -17592,7 +18093,11 @@ function assertPointerActionOptions(method, options) {
17592
18093
  const value = options[key];
17593
18094
  if (value instanceof Boolean) options[key] = value.valueOf();
17594
18095
  }
17595
- for (const key of ["delay", "clickCount"]) {
18096
+ for (const key of [
18097
+ "delay",
18098
+ "clickCount",
18099
+ "steps"
18100
+ ]) {
17596
18101
  const value = options[key];
17597
18102
  if (value instanceof Number) options[key] = value.valueOf();
17598
18103
  }
@@ -17610,8 +18115,12 @@ function assertPointerActionOptions(method, options) {
17610
18115
  "right"
17611
18116
  ].includes(options.button)) throw new TypeError("button: expected one of (left|right|middle)");
17612
18117
  if (options.scroll !== void 0 && !["auto", "none"].includes(options.scroll)) throw new TypeError("scroll: expected one of (auto|none)");
17613
- for (const key of ["delay", "clickCount"]) if (options[key] !== void 0 && (typeof options[key] !== "number" || !Number.isFinite(options[key]))) throw new TypeError(`${key}: expected number`);
17614
- if (options.clickCount !== void 0 && !Number.isInteger(options.clickCount)) throw new TypeError(`clickCount: expected integer, got float ${options.clickCount}`);
18118
+ for (const key of [
18119
+ "delay",
18120
+ "clickCount",
18121
+ "steps"
18122
+ ]) if (options[key] !== void 0 && (typeof options[key] !== "number" || !Number.isFinite(options[key]))) throw new TypeError(`${key}: expected number`);
18123
+ for (const key of ["clickCount", "steps"]) if (options[key] !== void 0 && !Number.isInteger(options[key])) throw new TypeError(`${key}: expected integer, got float ${options[key]}`);
17615
18124
  if (options.modifiers !== void 0 && (!Array.isArray(options.modifiers) || options.modifiers.some((value) => ![
17616
18125
  "Alt",
17617
18126
  "Control",
@@ -17658,16 +18167,79 @@ function assertElementHandleStateOptions(state, options) {
17658
18167
  "disabled",
17659
18168
  "editable"
17660
18169
  ].includes(state)) throw new Error(`Unsupported element state: ${state}`);
17661
- for (const key of Object.keys(options)) if (key !== "timeout") throw new Error(`Unsupported waitForElementState option: ${key}`);
18170
+ for (const key of Object.keys(options)) if (key !== "signal" && key !== "timeout") throw new Error(`Unsupported waitForElementState option: ${key}`);
18171
+ validateSignal("waitForElementState", options.signal);
17662
18172
  if (options.timeout !== void 0) validateTimeout(options.timeout, "waitForElementState timeout");
17663
18173
  }
18174
+ /**
18175
+ * Pinned 26a9e47 client/frame.ts `verifyLoadState`: accepts the four lifecycle
18176
+ * events, keeps the `networkidle0` alias, and rejects anything else with the
18177
+ * client's wording before the navigation is requested.
18178
+ */
18179
+ function verifyLoadState(name, waitUntil) {
18180
+ if (waitUntil === "networkidle0") waitUntil = "networkidle";
18181
+ if (![
18182
+ "load",
18183
+ "domcontentloaded",
18184
+ "networkidle",
18185
+ "commit"
18186
+ ].includes(waitUntil)) throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`);
18187
+ return waitUntil;
18188
+ }
17664
18189
  function isRetryableQueryError(error) {
17665
18190
  const message = asError(error).message;
17666
18191
  return message.startsWith("No elements found for locator") || message === "Element is not connected";
17667
18192
  }
18193
+ /**
18194
+ * Mirrors the pinned client's convertSelectOptionValues, which lets the first
18195
+ * entry decide whether the list is read as plain values/labels, followed by the
18196
+ * FrameSelectOptionParams protocol validation of every entry.
18197
+ */
18198
+ function selectOptionValues(values, evaluation) {
18199
+ if (values === null) return [];
18200
+ const list = Array.isArray(values) ? values : [values];
18201
+ list.forEach((value, index) => {
18202
+ if (value === null) throw new Error(`options[${index}]: expected object, got null`);
18203
+ });
18204
+ if (list[0] instanceof AdapterElementHandle) return list.map((value) => value.valueForEvaluation(evaluation));
18205
+ if (typeof list[0] === "string" || list[0] instanceof String) return list.map((value, index) => ({ valueOrLabel: validateString(value, `options[${index}].valueOrLabel`) }));
18206
+ return list.map((value, index) => validateSelectOptionValue(value, `options[${index}]`));
18207
+ }
18208
+ function validateSelectOptionValue(value, name) {
18209
+ if (typeof value !== "object") throw new Error(`${name}: expected object, got ${typeof value}`);
18210
+ const source = value;
18211
+ const option = {};
18212
+ for (const key of [
18213
+ "valueOrLabel",
18214
+ "value",
18215
+ "label"
18216
+ ]) if (source[key] !== void 0) option[key] = validateString(source[key], `${name}.${key}`);
18217
+ if (source.index !== void 0) option.index = validateInteger(source.index, `${name}.index`);
18218
+ return option;
18219
+ }
17668
18220
  function formatLocator(selector) {
17669
18221
  return `locator('${selector.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}')`;
17670
18222
  }
18223
+ /**
18224
+ * The call log line naming what a query waited for. A handle already holds its
18225
+ * element, so pinned ElementHandle diagnostics name no locator to wait for.
18226
+ */
18227
+ function queryCallLog(selector) {
18228
+ if (typeof selector !== "string") return "";
18229
+ return `\nCall log:\n - waiting for ${formatLocator(selector)}`;
18230
+ }
18231
+ /**
18232
+ * Pinned Playwright reports an InjectedScript fill rejection through the
18233
+ * calling member and the action's call log, not as the bare injected message:
18234
+ * `page.fill: Error: Element is not an <input>, <textarea> or [contenteditable]
18235
+ * element` followed by `Call log:`. `label` carries the Page form the way
18236
+ * performPointerAction derives its prefix.
18237
+ */
18238
+ function injectedFillError(error, selector, label, apiMethod, force) {
18239
+ const prefix = label.startsWith("page.fill(") ? "page.fill" : label.startsWith("elementHandle.") ? label : `locator.${apiMethod}`;
18240
+ const waitingFor = typeof selector === "string" ? `\n - waiting for ${formatLocator(selector)}` : "";
18241
+ return new Error(`${prefix}: Error: ${error.message}\nCall log:${waitingFor}\n - attempting fill action` + (force ? "" : "\n - waiting for element to be visible, enabled and editable"), { cause: error });
18242
+ }
17671
18243
  function presentOriginalXPath(error, selector) {
17672
18244
  const source = asError(error);
17673
18245
  if (!selector.startsWith("//")) return source;