Bin
2025-12-16 9e0b2ba2c317b1a86212f24cbae3195ad1f3dbfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { withMedia } from "../utils/media/MediaMixin";
import type { ViewWithMedia } from "../utils/media/types";
 
class ParagraphsHelper extends withMedia(
  class implements ViewWithMedia {
    get _baseRootSelector() {
      return ".lsf-paragraphs";
    }
 
    _rootSelector: string;
 
    constructor(rootSelector: string) {
      this._rootSelector = rootSelector.replace(/^\&/, this._baseRootSelector);
    }
 
    get root() {
      return cy.get(this._rootSelector);
    }
 
    get mediaElement() {
      return this.root.get("audio[controls]");
    }
 
    getPhrase(idx: number) {
      return this.root.find(`[data-testid="phrase:${idx}"]`);
    }
    getPhrasePlayButton(idx: number, timeout = 4000) {
      return this.getPhrase(idx).find("button[aria-label='play']", { timeout });
    }
    getPhrasePauseButton(idx: number, timeout = 4000) {
      return this.getPhrase(idx).find("button[aria-label='pause']", { timeout });
    }
 
    hasPhrasePlaying(idx: number, timeout = 4000) {
      this.getPhrasePauseButton(idx, timeout).should("exist");
    }
    hasNoPhrasePlaying(idx: number, timeout = 4000) {
      this.getPhrasePlayButton(idx, timeout).should("exist");
    }
 
    selectText(text: string, phraseIdx?: number) {
      const target = phraseIdx !== undefined ? this.getPhrase(phraseIdx) : this.root;
 
      return target.contains(text).then(($el) => {
        const el = $el[0];
        const textElement = el.childNodes[0];
        const startOffset = el.textContent.indexOf(text);
        const endOffset = startOffset + text.length;
        const document = el.ownerDocument;
        const range = document.createRange();
        range.setStart(textElement, startOffset);
        range.setEnd(textElement, endOffset);
        this._selectRange(range);
      });
    }
 
    _selectRange(range: Range) {
      const el: HTMLElement = (
        range.commonAncestorContainer.nodeType === Node.TEXT_NODE
          ? range.commonAncestorContainer.parentElement
          : range.commonAncestorContainer
      ) as HTMLElement;
      const elRect = el.getBoundingClientRect();
      const startEdgeRange = range.cloneRange();
      startEdgeRange.setEnd(range.startContainer, range.startOffset);
      const endEdgeRange = range.cloneRange();
      endEdgeRange.setStart(range.endContainer, range.endOffset);
      const startRect = startEdgeRange.getBoundingClientRect();
      const endRect = endEdgeRange.getBoundingClientRect();
      const x = startRect.left - elRect.left;
      const y = startRect.top - elRect.top;
      const x2 = endRect.right - elRect.left;
      const y2 = endRect.bottom - elRect.top;
      const eventOptions = {
        eventConstructor: "MouseEvent",
        buttons: 1,
        force: true,
      };
      cy.wrap(el)
        .trigger("mousedown", x, y, eventOptions)
        .trigger("mousemove", x2, y2, eventOptions)
        .then(() => {
          const document = el.ownerDocument;
          const selection = document.getSelection();
          selection.removeAllRanges();
          selection.addRange(range);
        })
        .trigger("mouseup", x2, y2, eventOptions);
    }
  },
) {}
 
const Paragraphs = new ParagraphsHelper("&:eq(0)");
const useParagraphs = (rootSelector: string) => {
  return new ParagraphsHelper(rootSelector);
};
 
export { Paragraphs, useParagraphs };