@gtkx/testing 1.0.0-rc.2 → 1.0.0-rc.4

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 (121) hide show
  1. package/README.md +4 -5
  2. package/dist/act.d.ts +2 -0
  3. package/dist/act.d.ts.map +1 -1
  4. package/dist/act.js.map +1 -1
  5. package/dist/bound-queries.d.ts +2 -3
  6. package/dist/bound-queries.d.ts.map +1 -1
  7. package/dist/bound-queries.js.map +1 -1
  8. package/dist/build-queries.d.ts.map +1 -1
  9. package/dist/build-queries.js +18 -7
  10. package/dist/build-queries.js.map +1 -1
  11. package/dist/config.d.ts +1 -0
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +3 -3
  14. package/dist/config.js.map +1 -1
  15. package/dist/errors.js +2 -2
  16. package/dist/errors.js.map +1 -1
  17. package/dist/index.d.ts +7 -4
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +4 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/matchers.d.ts +125 -21
  22. package/dist/matchers.d.ts.map +1 -1
  23. package/dist/matchers.js +258 -21
  24. package/dist/matchers.js.map +1 -1
  25. package/dist/normalize.d.ts +10 -0
  26. package/dist/normalize.d.ts.map +1 -0
  27. package/dist/normalize.js +20 -0
  28. package/dist/normalize.js.map +1 -0
  29. package/dist/pretty-widget.d.ts +2 -1
  30. package/dist/pretty-widget.d.ts.map +1 -1
  31. package/dist/pretty-widget.js +3 -3
  32. package/dist/pretty-widget.js.map +1 -1
  33. package/dist/queries.d.ts +4 -21
  34. package/dist/queries.d.ts.map +1 -1
  35. package/dist/queries.js +46 -59
  36. package/dist/queries.js.map +1 -1
  37. package/dist/render.js +3 -3
  38. package/dist/render.js.map +1 -1
  39. package/dist/suggestions.d.ts +3 -0
  40. package/dist/suggestions.d.ts.map +1 -1
  41. package/dist/suggestions.js.map +1 -1
  42. package/dist/traversal.d.ts +5 -0
  43. package/dist/traversal.d.ts.map +1 -1
  44. package/dist/traversal.js +1 -0
  45. package/dist/traversal.js.map +1 -1
  46. package/dist/types.d.ts +69 -5
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js.map +1 -1
  49. package/dist/user-event/adjustment.d.ts +13 -0
  50. package/dist/user-event/adjustment.d.ts.map +1 -1
  51. package/dist/user-event/adjustment.js +11 -0
  52. package/dist/user-event/adjustment.js.map +1 -1
  53. package/dist/user-event/click.d.ts +7 -0
  54. package/dist/user-event/click.d.ts.map +1 -1
  55. package/dist/user-event/click.js +7 -0
  56. package/dist/user-event/click.js.map +1 -1
  57. package/dist/user-event/controller.d.ts +31 -1
  58. package/dist/user-event/controller.d.ts.map +1 -1
  59. package/dist/user-event/controller.js +36 -1
  60. package/dist/user-event/controller.js.map +1 -1
  61. package/dist/user-event/gesture.d.ts +51 -0
  62. package/dist/user-event/gesture.d.ts.map +1 -1
  63. package/dist/user-event/gesture.js +47 -4
  64. package/dist/user-event/gesture.js.map +1 -1
  65. package/dist/user-event/index.d.ts +27 -0
  66. package/dist/user-event/index.d.ts.map +1 -1
  67. package/dist/user-event/index.js.map +1 -1
  68. package/dist/user-event/keyboard.d.ts +4 -2
  69. package/dist/user-event/keyboard.d.ts.map +1 -1
  70. package/dist/user-event/keyboard.js +13 -12
  71. package/dist/user-event/keyboard.js.map +1 -1
  72. package/dist/user-event/pointer.js +5 -5
  73. package/dist/user-event/pointer.js.map +1 -1
  74. package/dist/user-event/selection.d.ts +15 -0
  75. package/dist/user-event/selection.d.ts.map +1 -1
  76. package/dist/user-event/selection.js +15 -0
  77. package/dist/user-event/selection.js.map +1 -1
  78. package/dist/user-event/state.d.ts +1 -1
  79. package/dist/user-event/state.d.ts.map +1 -1
  80. package/dist/user-event/state.js +1 -1
  81. package/dist/user-event/state.js.map +1 -1
  82. package/dist/user-event/text.d.ts +30 -3
  83. package/dist/user-event/text.d.ts.map +1 -1
  84. package/dist/user-event/text.js +28 -1
  85. package/dist/user-event/text.js.map +1 -1
  86. package/dist/wait-for.d.ts +2 -0
  87. package/dist/wait-for.d.ts.map +1 -1
  88. package/dist/wait-for.js.map +1 -1
  89. package/dist/widget-accessible-properties.d.ts +28 -2
  90. package/dist/widget-accessible-properties.d.ts.map +1 -1
  91. package/dist/widget-accessible-properties.js +129 -10
  92. package/dist/widget-accessible-properties.js.map +1 -1
  93. package/dist/within.js.map +1 -1
  94. package/package.json +7 -7
  95. package/src/act.ts +2 -0
  96. package/src/bound-queries.ts +2 -3
  97. package/src/build-queries.ts +20 -8
  98. package/src/config.ts +4 -3
  99. package/src/errors.ts +2 -2
  100. package/src/index.ts +11 -2
  101. package/src/matchers.ts +500 -53
  102. package/src/normalize.ts +28 -0
  103. package/src/pretty-widget.ts +5 -4
  104. package/src/queries.ts +79 -105
  105. package/src/render.tsx +3 -3
  106. package/src/suggestions.ts +3 -0
  107. package/src/traversal.ts +5 -0
  108. package/src/types.ts +88 -4
  109. package/src/user-event/adjustment.ts +13 -0
  110. package/src/user-event/click.ts +7 -0
  111. package/src/user-event/controller.ts +50 -1
  112. package/src/user-event/gesture.ts +57 -6
  113. package/src/user-event/index.ts +27 -0
  114. package/src/user-event/keyboard.ts +18 -16
  115. package/src/user-event/pointer.ts +5 -5
  116. package/src/user-event/selection.ts +15 -0
  117. package/src/user-event/state.ts +2 -2
  118. package/src/user-event/text.ts +31 -4
  119. package/src/wait-for.ts +2 -0
  120. package/src/widget-accessible-properties.ts +188 -10
  121. package/src/within.ts +1 -1
@@ -1,59 +1,163 @@
1
+ import * as Gtk from "@gtkx/gi/gtk";
1
2
  /** The expected value for a text matcher: an exact string or a regular expression. */
2
3
  type TextExpectation = string | RegExp;
4
+ /** Options controlling how `toHaveTextContent` normalizes the text it reads. */
5
+ type TextContentOptions = {
6
+ /**
7
+ * When true (the default), trim the text and collapse runs of whitespace into single spaces
8
+ * before comparing. When false, only replace non-breaking spaces with regular ones.
9
+ */
10
+ normalizeWhitespace?: boolean | undefined;
11
+ };
12
+ /** The expected value for a style class: an exact class name or a regular expression. */
13
+ type ClassExpectation = string | RegExp;
14
+ /** The outcome of a matcher: whether it passed, and the failure text built on demand. */
3
15
  type MatcherResult = {
4
16
  pass: boolean;
5
17
  message: () => string;
6
18
  };
19
+ /** The matcher state bound as `this`, supplying the test runner's deep equality check. */
20
+ type MatcherContext = {
21
+ equals: (actual: unknown, expected: unknown) => boolean;
22
+ };
23
+ /** Compares text read from the received widget; with no expected value, asserts the text is non-empty. */
7
24
  type TextMatcher = (received: unknown, expected?: TextExpectation) => MatcherResult;
25
+ /** Asserts a single state of the received widget, taking no expected value. */
8
26
  type StateMatcher = (received: unknown) => MatcherResult;
9
- type ValueMatcher = (received: unknown, expected: number) => MatcherResult;
27
+ /** A text matcher that also takes normalization options for the text it reads. */
28
+ type TextContentMatcher = (received: unknown, expected?: TextExpectation, options?: TextContentOptions) => MatcherResult;
29
+ /** Signatures of the widget assertion matchers, keyed by the name each is registered under. */
10
30
  type MatcherImplementations = {
31
+ /** Asserts the text an editable widget or combo box shows; with no argument, that it is not empty. */
11
32
  toHaveDisplayValue: TextMatcher;
12
- toHaveTextContent: TextMatcher;
33
+ /** Asserts the widget's own text, or its descendants' when it has none, contains or matches the expectation. */
34
+ toHaveTextContent: TextContentMatcher;
35
+ /** Asserts the widget's accessible name; with no argument, that it has one. */
13
36
  toHaveAccessibleName: TextMatcher;
37
+ /**
38
+ * Asserts the joined accessible names of the widget's `described-by` targets, falling back to its
39
+ * `description` and then to its tooltip.
40
+ */
41
+ toHaveAccessibleDescription: TextMatcher;
42
+ /** Asserts the joined accessible names of the widget's `error-message` targets, read only while it is invalid. */
43
+ toHaveAccessibleErrorMessage: TextMatcher;
44
+ /** Asserts the widget's placeholder text; with no argument, that it has some. */
14
45
  toHavePlaceholderText: TextMatcher;
46
+ /** Asserts the text currently selected in an editable widget. */
47
+ toHaveSelection: TextMatcher;
48
+ /** Asserts the widget's checked state is checked rather than unchecked or mixed. */
15
49
  toBeChecked: StateMatcher;
50
+ /** Asserts the widget's checked state is mixed. */
51
+ toBePartiallyChecked: StateMatcher;
52
+ /** Asserts a `Gtk.ToggleButton` is active, and throws for any other widget. */
16
53
  toBePressed: StateMatcher;
54
+ /** Asserts a `Gtk.Expander` or the row behind a `Gtk.TreeExpander` is expanded, and throws for anything else. */
17
55
  toBeExpanded: StateMatcher;
56
+ /**
57
+ * Asserts a `Gtk.ListBoxRow` or `Gtk.FlowBoxChild` is selected, or that a widget in a selectable role
58
+ * carries the selected state flag, and throws for anything else.
59
+ */
18
60
  toBeSelected: StateMatcher;
19
- toHaveValue: ValueMatcher;
61
+ /** Asserts the widget is insensitive, or sits inside an insensitive ancestor. */
62
+ toBeDisabled: StateMatcher;
63
+ /** Asserts the widget and all of its ancestors are sensitive. */
64
+ toBeEnabled: StateMatcher;
65
+ /** Asserts the widget and its ancestors are all visible, and that none of them is fully transparent. */
66
+ toBeVisible: StateMatcher;
67
+ /** Asserts the widget's root is a window that is still in the toplevel list. */
68
+ toBeRooted: StateMatcher;
69
+ /** Asserts the widget has neither a child nor label text. */
70
+ toBeEmpty: StateMatcher;
71
+ /** Asserts the widget's accessible invalid state is set to anything other than false. */
72
+ toBeInvalid: StateMatcher;
73
+ /** Asserts the widget's accessible invalid state is unset or false. */
74
+ toBeValid: StateMatcher;
75
+ /** Asserts the widget's accessible required state. */
76
+ toBeRequired: StateMatcher;
77
+ /** Asserts the widget holds the platform focus state. */
78
+ toHaveFocus: StateMatcher;
79
+ /** Asserts a widget's numeric value, or its display value when a string is given. */
80
+ toHaveValue: (received: unknown, expected?: number | string) => MatcherResult;
81
+ /** Asserts the widget's accessible role. */
82
+ toHaveRole: (received: unknown, expected: Gtk.AccessibleRole) => MatcherResult;
83
+ /** Asserts the widget is, or is an ancestor of, the given widget. */
84
+ toContainElement: (received: unknown, descendant: Gtk.Widget | null) => MatcherResult;
85
+ /**
86
+ * Asserts the widget carries every given style class, each a name, a space-separated list, or a pattern.
87
+ * Pass `{ exact: true }` last to require exactly that set, which rules out patterns.
88
+ */
89
+ toHaveClass: (received: unknown, ...args: unknown[]) => MatcherResult;
90
+ /**
91
+ * Asserts a GObject property, named as in GObject and looked up by its camel-cased accessor, equals the
92
+ * expected value. With no expected value, asserts the property is set. GObject values compare by identity.
93
+ */
94
+ toHaveObjectProperty: (this: MatcherContext, received: unknown, ...args: unknown[]) => MatcherResult;
20
95
  };
21
- declare const toHaveDisplayValue: TextMatcher;
22
- declare const toHaveTextContent: TextMatcher;
23
96
  declare const toHaveAccessibleName: TextMatcher;
97
+ declare const toHaveAccessibleDescription: TextMatcher;
98
+ declare const toHaveAccessibleErrorMessage: TextMatcher;
24
99
  declare const toHavePlaceholderText: TextMatcher;
25
- declare const toBeChecked: StateMatcher;
100
+ declare const toHaveSelection: TextMatcher;
26
101
  declare const toBePressed: StateMatcher;
27
102
  declare const toBeExpanded: StateMatcher;
28
103
  declare const toBeSelected: StateMatcher;
104
+ declare const toBeRequired: StateMatcher;
29
105
  /** The widget assertion matchers keyed by name, suitable for passing to `expect.extend`. */
30
106
  declare const matchers: MatcherImplementations;
31
- declare function toHaveValue(received: unknown, expected: number): MatcherResult;
107
+ declare function toHaveTextContent(received: unknown, expected?: TextExpectation, options?: TextContentOptions): MatcherResult;
108
+ declare function toBeChecked(received: unknown): MatcherResult;
109
+ declare function toBePartiallyChecked(received: unknown): MatcherResult;
110
+ declare function toHaveDisplayValue(received: unknown, expected?: TextExpectation): MatcherResult;
111
+ declare function toHaveValue(received: unknown, expected?: number | string): MatcherResult;
112
+ declare function toBeDisabled(received: unknown): MatcherResult;
113
+ declare function toBeEnabled(received: unknown): MatcherResult;
114
+ declare function toBeVisible(received: unknown): MatcherResult;
115
+ declare function toBeRooted(received: unknown): MatcherResult;
116
+ declare function toBeEmpty(received: unknown): MatcherResult;
117
+ declare function toBeInvalid(received: unknown): MatcherResult;
118
+ declare function toBeValid(received: unknown): MatcherResult;
119
+ declare function toHaveFocus(received: unknown): MatcherResult;
120
+ declare function toHaveRole(received: unknown, expected: Gtk.AccessibleRole): MatcherResult;
121
+ declare function toContainElement(received: unknown, descendant: Gtk.Widget | null): MatcherResult;
122
+ declare function toHaveClass(received: unknown, ...args: unknown[]): MatcherResult;
123
+ declare function toHaveObjectProperty(this: MatcherContext, received: unknown, ...args: unknown[]): MatcherResult;
32
124
  /** Registers the widget matchers on the global `expect`, when one is available. Safe to call more than once. */
33
125
  declare const registerMatchers: () => void;
34
126
  declare module "@vitest/expect" {
35
- interface Assertion {
127
+ interface WidgetMatchers {
36
128
  toHaveDisplayValue(expected?: TextExpectation): void;
37
- toHaveTextContent(expected?: TextExpectation): void;
129
+ toHaveTextContent(expected?: TextExpectation, options?: TextContentOptions): void;
38
130
  toHaveAccessibleName(expected?: TextExpectation): void;
131
+ toHaveAccessibleDescription(expected?: TextExpectation): void;
132
+ toHaveAccessibleErrorMessage(expected?: TextExpectation): void;
39
133
  toHavePlaceholderText(expected?: TextExpectation): void;
134
+ toHaveSelection(expected?: TextExpectation): void;
40
135
  toBeChecked(): void;
136
+ toBePartiallyChecked(): void;
41
137
  toBePressed(): void;
42
138
  toBeExpanded(): void;
43
139
  toBeSelected(): void;
44
- toHaveValue(expected: number): void;
140
+ toBeDisabled(): void;
141
+ toBeEnabled(): void;
142
+ toBeVisible(): void;
143
+ toBeRooted(): void;
144
+ toBeEmpty(): void;
145
+ toBeInvalid(): void;
146
+ toBeValid(): void;
147
+ toBeRequired(): void;
148
+ toHaveFocus(): void;
149
+ toHaveValue(expected?: number | string): void;
150
+ toHaveRole(expected: Gtk.AccessibleRole): void;
151
+ toContainElement(descendant: Gtk.Widget | null): void;
152
+ toHaveClass(...args: (ClassExpectation | {
153
+ exact: boolean;
154
+ })[]): void;
155
+ toHaveObjectProperty(name: string, expected?: unknown): void;
45
156
  }
46
- interface AsymmetricMatchersContaining {
47
- toHaveDisplayValue(expected?: TextExpectation): void;
48
- toHaveTextContent(expected?: TextExpectation): void;
49
- toHaveAccessibleName(expected?: TextExpectation): void;
50
- toHavePlaceholderText(expected?: TextExpectation): void;
51
- toBeChecked(): void;
52
- toBePressed(): void;
53
- toBeExpanded(): void;
54
- toBeSelected(): void;
55
- toHaveValue(expected: number): void;
157
+ interface Assertion extends WidgetMatchers {
158
+ }
159
+ interface AsymmetricMatchersContaining extends WidgetMatchers {
56
160
  }
57
161
  }
58
- export { toHaveDisplayValue, toHaveTextContent, toHaveAccessibleName, toHavePlaceholderText, toBeChecked, toBePressed, toBeExpanded, toBeSelected, matchers, toHaveValue, registerMatchers, type TextExpectation, };
162
+ export { toHaveDisplayValue, toHaveTextContent, toHaveAccessibleName, toHaveAccessibleDescription, toHaveAccessibleErrorMessage, toHavePlaceholderText, toHaveSelection, toBeChecked, toBePartiallyChecked, toBePressed, toBeExpanded, toBeSelected, toBeDisabled, toBeEnabled, toBeVisible, toBeRooted, toBeEmpty, toBeInvalid, toBeValid, toBeRequired, toHaveFocus, toHaveValue, toHaveRole, toContainElement, toHaveClass, toHaveObjectProperty, matchers, registerMatchers, type ClassExpectation, type TextContentOptions, type TextExpectation, };
59
163
  //# sourceMappingURL=matchers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"AAcA,sFAAsF;AACtF,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AACvC,KAAK,aAAa,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,MAAM,CAAA;CAAE,CAAC;AAC9D,KAAK,WAAW,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,eAAe,KAAK,aAAa,CAAC;AACpF,KAAK,YAAY,GAAG,CAAC,QAAQ,EAAE,OAAO,KAAK,aAAa,CAAC;AACzD,KAAK,YAAY,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,aAAa,CAAC;AAG3E,KAAK,sBAAsB,GAAG;IAC1B,kBAAkB,EAAE,WAAW,CAAC;IAChC,iBAAiB,EAAE,WAAW,CAAC;IAC/B,oBAAoB,EAAE,WAAW,CAAC;IAClC,qBAAqB,EAAE,WAAW,CAAC;IACnC,WAAW,EAAE,YAAY,CAAC;IAC1B,WAAW,EAAE,YAAY,CAAC;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,YAAY,CAAC;CAC7B,CAAC;AAIF,QAAA,MAAM,kBAAkB,EAAE,WAA+E,CAAC;AAE1G,QAAA,MAAM,iBAAiB,EAAE,WAIxB,CAAC;AAEF,QAAA,MAAM,oBAAoB,EAAE,WAAmF,CAAC;AAEhH,QAAA,MAAM,qBAAqB,EAAE,WAI5B,CAAC;AAEF,QAAA,MAAM,WAAW,EAAE,YAAmF,CAAC;AACvG,QAAA,MAAM,WAAW,EAAE,YAAmF,CAAC;AACvG,QAAA,MAAM,YAAY,EAAE,YAAsF,CAAC;AAC3G,QAAA,MAAM,YAAY,EAAE,YAAsF,CAAC;AAE3G,4FAA4F;AAC5F,QAAA,MAAM,QAAQ,EAAE,sBAUf,CAAC;AA8FF,iBAAS,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAmBvE;AAYD,gHAAgH;AAChH,QAAA,MAAM,gBAAgB,QAAO,IAa5B,CAAC;AAEF,OAAO,QAAQ,gBAAgB,CAAC;IAE5B,UAAU,SAAS;QACf,kBAAkB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACrD,iBAAiB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACpD,oBAAoB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACvD,qBAAqB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACxD,WAAW,IAAI,IAAI,CAAC;QACpB,WAAW,IAAI,IAAI,CAAC;QACpB,YAAY,IAAI,IAAI,CAAC;QACrB,YAAY,IAAI,IAAI,CAAC;QACrB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACvC;IAED,UAAU,4BAA4B;QAClC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACrD,iBAAiB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACpD,oBAAoB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACvD,qBAAqB,CAAC,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACxD,WAAW,IAAI,IAAI,CAAC;QACpB,WAAW,IAAI,IAAI,CAAC;QACpB,YAAY,IAAI,IAAI,CAAC;QACrB,YAAY,IAAI,IAAI,CAAC;QACrB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACvC;CAEJ;AAED,OAAO,EACH,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,gBAAgB,EAChB,KAAK,eAAe,GACvB,CAAC"}
1
+ {"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"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"}
package/dist/matchers.js CHANGED
@@ -1,38 +1,67 @@
1
1
  /// <reference types="@vitest/expect" />
2
+ import * as GObject from "@gtkx/gi/gobject";
2
3
  import * as Gtk from "@gtkx/gi/gtk";
3
- import { getWidgetAccessibleName, getWidgetCheckedState, getWidgetDisplayValue, getWidgetExpandedState, getWidgetNodeText, getWidgetPlaceholderText, getWidgetPressedState, getWidgetSelectedState, getWidgetValue, } from "./widget-accessible-properties.js";
4
- const toHaveDisplayValue = textMatcher("toHaveDisplayValue", getWidgetDisplayValue, "exact");
5
- const toHaveTextContent = textMatcher("toHaveTextContent", (widget) => getWidgetNodeText(widget) ?? getWidgetAccessibleName(widget), "substring");
4
+ import { getDefaultNormalizer } from "./normalize.js";
5
+ import { formatRole } from "./role-helpers.js";
6
+ import { getWidgetAccessibleName, getWidgetCheckedState, getWidgetDescribedByText, getWidgetDisplayValue, getWidgetErrorMessage, getWidgetExpandedState, getWidgetInvalidState, getWidgetLabelText, getWidgetPlaceholderText, getWidgetPressedState, getWidgetRequiredState, getWidgetSelectedState, getWidgetSelection, getWidgetTextContent, getWidgetValue, hasDisplayValue, isWidgetDisabled, isWidgetVisible, } from "./widget-accessible-properties.js";
7
+ const registration = { isRegistered: false };
8
+ const displayValueMatcher = textMatcher("toHaveDisplayValue", getWidgetDisplayValue, "exact");
6
9
  const toHaveAccessibleName = textMatcher("toHaveAccessibleName", getWidgetAccessibleName, "exact");
10
+ const toHaveAccessibleDescription = textMatcher("toHaveAccessibleDescription", getWidgetDescribedByText, "exact");
11
+ const toHaveAccessibleErrorMessage = textMatcher("toHaveAccessibleErrorMessage", readErrorMessageText, "exact");
7
12
  const toHavePlaceholderText = textMatcher("toHavePlaceholderText", getWidgetPlaceholderText, "exact");
8
- const toBeChecked = booleanStateMatcher("toBeChecked", "checked", getWidgetCheckedState);
13
+ const toHaveSelection = textMatcher("toHaveSelection", getWidgetSelection, "exact");
9
14
  const toBePressed = booleanStateMatcher("toBePressed", "pressed", getWidgetPressedState);
10
15
  const toBeExpanded = booleanStateMatcher("toBeExpanded", "expanded", getWidgetExpandedState);
11
16
  const toBeSelected = booleanStateMatcher("toBeSelected", "selected", getWidgetSelectedState);
17
+ const toBeRequired = booleanStateMatcher("toBeRequired", "required", getWidgetRequiredState);
12
18
  /** The widget assertion matchers keyed by name, suitable for passing to `expect.extend`. */
13
19
  const matchers = {
14
20
  toHaveDisplayValue,
15
21
  toHaveTextContent,
16
22
  toHaveAccessibleName,
23
+ toHaveAccessibleDescription,
24
+ toHaveAccessibleErrorMessage,
17
25
  toHavePlaceholderText,
26
+ toHaveSelection,
18
27
  toBeChecked,
28
+ toBePartiallyChecked,
19
29
  toBePressed,
20
30
  toBeExpanded,
21
31
  toBeSelected,
32
+ toBeDisabled,
33
+ toBeEnabled,
34
+ toBeVisible,
35
+ toBeRooted,
36
+ toBeEmpty,
37
+ toBeInvalid,
38
+ toBeValid,
39
+ toBeRequired,
40
+ toHaveFocus,
22
41
  toHaveValue,
42
+ toHaveRole,
43
+ toContainElement,
44
+ toHaveClass,
45
+ toHaveObjectProperty,
23
46
  };
24
- const registration = { isRegistered: false };
25
47
  const asWidget = (received, matcherName) => {
26
48
  if (!(received instanceof Gtk.Widget)) {
27
49
  throw new TypeError(`${matcherName}: received value must be a Gtk.Widget, got ${typeof received}`);
28
50
  }
29
51
  return received;
30
52
  };
53
+ const asObject = (received, matcherName) => {
54
+ if (!(received instanceof GObject.Object)) {
55
+ throw new TypeError(`${matcherName}: received value must be a GObject, got ${typeof received}`);
56
+ }
57
+ return received;
58
+ };
31
59
  const describeWidget = (widget) => {
32
60
  const role = Gtk.AccessibleRole[widget.getAccessibleRole()];
33
61
  const name = getWidgetAccessibleName(widget);
34
62
  return name === null ? `<${role}>` : `<${role} name=${JSON.stringify(name)}>`;
35
63
  };
64
+ const describeObject = (object) => object instanceof Gtk.Widget ? describeWidget(object) : `<${object.constructor.name}>`;
36
65
  const isTextMatch = (actual, expected, mode) => {
37
66
  if (expected instanceof RegExp) {
38
67
  expected.lastIndex = 0;
@@ -55,6 +84,89 @@ const matchedResult = (context, expected, isPass) => ({
55
84
  message: () => `expected widget ${negationPrefix(isPass)}${context.matcherName} ${describeExpected(expected)}, ` +
56
85
  `but received ${JSON.stringify(context.actual)}\n${describeWidget(context.widget)}`,
57
86
  });
87
+ const stateResult = (widget, stateName, isPass) => ({
88
+ pass: isPass,
89
+ message: () => `expected widget ${negationPrefix(isPass)}to be ${stateName}\n${describeWidget(widget)}`,
90
+ });
91
+ const camelCase = (name) => name.replaceAll(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
92
+ const isAsymmetricMatcher = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "asymmetricMatch") === "function";
93
+ const isEqualValue = (context, actual, expected) => {
94
+ if (isAsymmetricMatcher(expected)) {
95
+ return context.equals(actual, expected);
96
+ }
97
+ if (actual instanceof GObject.Object || expected instanceof GObject.Object) {
98
+ return Object.is(actual, expected);
99
+ }
100
+ return context.equals(actual, expected);
101
+ };
102
+ const isClassMatch = (actual, expected) => expected instanceof RegExp ? actual.some((name) => expected.test(name)) : actual.includes(expected);
103
+ const isWidgetRooted = (widget) => {
104
+ const root = widget.getRoot();
105
+ if (root === null) {
106
+ return false;
107
+ }
108
+ if (root instanceof Gtk.Window) {
109
+ return Gtk.Window.listToplevels().includes(root);
110
+ }
111
+ return true;
112
+ };
113
+ const globalExpect = () => {
114
+ const candidate = Reflect.get(globalThis, "expect");
115
+ if (candidate && typeof candidate.extend === "function") {
116
+ return candidate;
117
+ }
118
+ return null;
119
+ };
120
+ function readErrorMessageText(widget) {
121
+ const state = getWidgetInvalidState(widget);
122
+ if (state === null || state === Gtk.AccessibleInvalidState.FALSE) {
123
+ return null;
124
+ }
125
+ const targets = getWidgetErrorMessage(widget);
126
+ if (targets === null) {
127
+ return null;
128
+ }
129
+ const texts = targets.map((target) => getWidgetAccessibleName(target)).filter((text) => text !== null);
130
+ return texts.length > 0 ? texts.join(" ") : null;
131
+ }
132
+ function assertReadableProperty(object, name, property, value) {
133
+ if (typeof value === "function") {
134
+ throw new TypeError(`toHaveObjectProperty: "${name}" is shadowed by a method of the same name; ` +
135
+ `call ${property}() and assert on its result instead`);
136
+ }
137
+ if (value === undefined && !Reflect.has(object, property)) {
138
+ throw new TypeError(`toHaveObjectProperty: no readable property "${name}" on ${describeObject(object)}; ` +
139
+ "construct-only and write-only properties cannot be read back");
140
+ }
141
+ }
142
+ function readObjectProperty(object, name) {
143
+ const property = camelCase(name);
144
+ const value = Reflect.get(object, property);
145
+ assertReadableProperty(object, name, property, value);
146
+ return value;
147
+ }
148
+ function classEntries(entry) {
149
+ return entry instanceof RegExp ? [entry] : String(entry).split(/\s+/).filter(Boolean);
150
+ }
151
+ function parseClassArguments(args) {
152
+ const last = args.at(-1);
153
+ const isOptions = typeof last === "object" && last !== null && !(last instanceof RegExp);
154
+ const isExact = isOptions && Reflect.get(last, "exact") === true;
155
+ const entries = isOptions ? args.slice(0, -1) : args;
156
+ return { expected: entries.flatMap((entry) => classEntries(entry)), isExact };
157
+ }
158
+ function exactClassResult(widget, actual, expected) {
159
+ if (expected.some((entry) => entry instanceof RegExp)) {
160
+ throw new TypeError("toHaveClass: the exact option cannot be combined with a regular expression");
161
+ }
162
+ const names = expected.map(String);
163
+ const isPass = names.length === actual.length && names.every((name) => actual.includes(name));
164
+ return {
165
+ pass: isPass,
166
+ message: () => `expected widget ${negationPrefix(isPass)}to have exactly the classes ${JSON.stringify(names)}, ` +
167
+ `but received ${JSON.stringify(actual)}\n${describeWidget(widget)}`,
168
+ };
169
+ }
58
170
  function textMatcher(matcherName, read, mode) {
59
171
  return (received, expected) => {
60
172
  const widget = asWidget(received, matcherName);
@@ -66,41 +178,166 @@ function textMatcher(matcherName, read, mode) {
66
178
  return matchedResult(context, expected, actual !== null && isTextMatch(actual, expected, mode));
67
179
  };
68
180
  }
181
+ function normalizeTextContent(text, options) {
182
+ if (options?.normalizeWhitespace === false) {
183
+ return text.replaceAll("\u{A0}", " ");
184
+ }
185
+ return getDefaultNormalizer()(text);
186
+ }
187
+ function readTextContent(widget, options) {
188
+ const text = getWidgetTextContent(widget);
189
+ return text === null ? null : normalizeTextContent(text, options);
190
+ }
191
+ function toHaveTextContent(received, expected, options) {
192
+ const read = (widget) => readTextContent(widget, options);
193
+ return textMatcher("toHaveTextContent", read, "substring")(received, expected);
194
+ }
195
+ function notApplicable(matcherName, stateName, widget) {
196
+ return new Error(`${matcherName}: widget does not expose a ${stateName} ` +
197
+ `(role ${Gtk.AccessibleRole[widget.getAccessibleRole()]})\n${describeWidget(widget)}`);
198
+ }
69
199
  function booleanStateMatcher(matcherName, stateName, read) {
70
200
  return (received) => {
71
201
  const widget = asWidget(received, matcherName);
72
202
  const state = read(widget);
73
203
  if (state === null) {
74
- throw new Error(`${matcherName}: widget does not expose a ${stateName} state ` +
75
- `(role ${Gtk.AccessibleRole[widget.getAccessibleRole()]})\n${describeWidget(widget)}`);
204
+ throw notApplicable(matcherName, `${stateName} state`, widget);
76
205
  }
77
- return {
78
- pass: state,
79
- message: () => `expected widget ${negationPrefix(state)}to be ${stateName}\n${describeWidget(widget)}`,
80
- };
206
+ return stateResult(widget, stateName, state);
81
207
  };
82
208
  }
209
+ function readCheckedState(widget, matcherName) {
210
+ const state = getWidgetCheckedState(widget);
211
+ if (state === null) {
212
+ throw notApplicable(matcherName, "checked state", widget);
213
+ }
214
+ return state;
215
+ }
216
+ function toBeChecked(received) {
217
+ const widget = asWidget(received, "toBeChecked");
218
+ return stateResult(widget, "checked", readCheckedState(widget, "toBeChecked") === "checked");
219
+ }
220
+ function toBePartiallyChecked(received) {
221
+ const widget = asWidget(received, "toBePartiallyChecked");
222
+ return stateResult(widget, "partially checked", readCheckedState(widget, "toBePartiallyChecked") === "mixed");
223
+ }
224
+ function toHaveDisplayValue(received, expected) {
225
+ const widget = asWidget(received, "toHaveDisplayValue");
226
+ if (!hasDisplayValue(widget)) {
227
+ throw notApplicable("toHaveDisplayValue", "display value", widget);
228
+ }
229
+ return displayValueMatcher(received, expected);
230
+ }
83
231
  function toHaveValue(received, expected) {
84
232
  const widget = asWidget(received, "toHaveValue");
233
+ if (typeof expected === "string") {
234
+ return displayValueMatcher(received, expected);
235
+ }
85
236
  const actual = getWidgetValue(widget).now;
86
237
  if (actual === null) {
87
- throw new Error("toHaveValue: widget does not expose a numeric value " +
88
- `(role ${Gtk.AccessibleRole[widget.getAccessibleRole()]})\n${describeWidget(widget)}`);
238
+ throw notApplicable("toHaveValue", "numeric value", widget);
89
239
  }
90
- const isPass = actual === expected;
240
+ const isPass = expected === undefined || actual === expected;
91
241
  return {
92
242
  pass: isPass,
93
243
  message: () => `expected widget ${negationPrefix(isPass)}to have value ${String(expected)}, ` +
94
244
  `but received ${String(actual)}\n${describeWidget(widget)}`,
95
245
  };
96
246
  }
97
- const globalExpect = () => {
98
- const candidate = Reflect.get(globalThis, "expect");
99
- if (candidate && typeof candidate.extend === "function") {
100
- return candidate;
247
+ function toBeDisabled(received) {
248
+ const widget = asWidget(received, "toBeDisabled");
249
+ return stateResult(widget, "disabled", isWidgetDisabled(widget));
250
+ }
251
+ function toBeEnabled(received) {
252
+ const widget = asWidget(received, "toBeEnabled");
253
+ return stateResult(widget, "enabled", !isWidgetDisabled(widget));
254
+ }
255
+ function toBeVisible(received) {
256
+ const widget = asWidget(received, "toBeVisible");
257
+ return stateResult(widget, "visible", isWidgetVisible(widget));
258
+ }
259
+ function toBeRooted(received) {
260
+ if (received === null) {
261
+ return { pass: false, message: () => "expected a widget to be rooted in a window, but received null" };
101
262
  }
102
- return null;
103
- };
263
+ const widget = asWidget(received, "toBeRooted");
264
+ return stateResult(widget, "rooted in a window", isWidgetRooted(widget));
265
+ }
266
+ function toBeEmpty(received) {
267
+ const widget = asWidget(received, "toBeEmpty");
268
+ return stateResult(widget, "empty", widget.getFirstChild() === null && getWidgetLabelText(widget) === null);
269
+ }
270
+ function toBeInvalid(received) {
271
+ const widget = asWidget(received, "toBeInvalid");
272
+ const state = getWidgetInvalidState(widget);
273
+ return stateResult(widget, "invalid", state !== null && state !== Gtk.AccessibleInvalidState.FALSE);
274
+ }
275
+ function toBeValid(received) {
276
+ const widget = asWidget(received, "toBeValid");
277
+ const state = getWidgetInvalidState(widget);
278
+ return stateResult(widget, "valid", state === null || state === Gtk.AccessibleInvalidState.FALSE);
279
+ }
280
+ function toHaveFocus(received) {
281
+ const widget = asWidget(received, "toHaveFocus");
282
+ return stateResult(widget, "focused", widget.getPlatformState(Gtk.AccessiblePlatformState.FOCUSED));
283
+ }
284
+ function toHaveRole(received, expected) {
285
+ const widget = asWidget(received, "toHaveRole");
286
+ const actual = widget.getAccessibleRole();
287
+ const isPass = actual === expected;
288
+ return {
289
+ pass: isPass,
290
+ message: () => `expected widget ${negationPrefix(isPass)}to have role '${formatRole(expected)}', ` +
291
+ `but received '${formatRole(actual)}'\n${describeWidget(widget)}`,
292
+ };
293
+ }
294
+ function toContainElement(received, descendant) {
295
+ const widget = asWidget(received, "toContainElement");
296
+ const isPass = descendant !== null && (descendant === widget || descendant.isAncestor(widget));
297
+ return {
298
+ pass: isPass,
299
+ message: () => `expected widget ${negationPrefix(isPass)}to contain ` +
300
+ `${descendant === null ? "null" : describeWidget(descendant)}\n${describeWidget(widget)}`,
301
+ };
302
+ }
303
+ function toHaveClass(received, ...args) {
304
+ const widget = asWidget(received, "toHaveClass");
305
+ const actual = widget.getCssClasses();
306
+ const { expected, isExact } = parseClassArguments(args);
307
+ if (isExact) {
308
+ return exactClassResult(widget, actual, expected);
309
+ }
310
+ if (expected.length === 0) {
311
+ return stateResult(widget, "given any style class", actual.length > 0);
312
+ }
313
+ const isPass = expected.every((entry) => isClassMatch(actual, entry));
314
+ return {
315
+ pass: isPass,
316
+ message: () => `expected widget ${negationPrefix(isPass)}to have class ${expected.map(String).join(", ")}, ` +
317
+ `but received ${JSON.stringify(actual)}\n${describeWidget(widget)}`,
318
+ };
319
+ }
320
+ function toHaveObjectProperty(received, ...args) {
321
+ const object = asObject(received, "toHaveObjectProperty");
322
+ const [name, expected] = args;
323
+ const actual = readObjectProperty(object, String(name));
324
+ if (args.length < 2) {
325
+ const isSet = actual !== null && actual !== undefined;
326
+ return {
327
+ pass: isSet,
328
+ message: () => `expected ${describeObject(object)} ${negationPrefix(isSet)}to have a value for property ` +
329
+ `"${String(name)}", but received ${JSON.stringify(actual)}`,
330
+ };
331
+ }
332
+ /* eslint-disable-next-line unicorn/no-this-outside-of-class --
333
+ expect.extend invokes matchers with the matcher state as `this` */
334
+ const isPass = isEqualValue(this, actual, expected);
335
+ return {
336
+ pass: isPass,
337
+ message: () => `expected ${describeObject(object)} ${negationPrefix(isPass)}to have property "${String(name)}" ` +
338
+ `equal to ${JSON.stringify(expected)}, but received ${JSON.stringify(actual)}`,
339
+ };
340
+ }
104
341
  /** Registers the widget matchers on the global `expect`, when one is available. Safe to call more than once. */
105
342
  const registerMatchers = () => {
106
343
  if (registration.isRegistered) {
@@ -113,5 +350,5 @@ const registerMatchers = () => {
113
350
  expect.extend(matchers);
114
351
  registration.isRegistered = true;
115
352
  };
116
- export { toHaveDisplayValue, toHaveTextContent, toHaveAccessibleName, toHavePlaceholderText, toBeChecked, toBePressed, toBeExpanded, toBeSelected, matchers, toHaveValue, registerMatchers, };
353
+ export { toHaveDisplayValue, toHaveTextContent, toHaveAccessibleName, toHaveAccessibleDescription, toHaveAccessibleErrorMessage, toHavePlaceholderText, toHaveSelection, toBeChecked, toBePartiallyChecked, toBePressed, toBeExpanded, toBeSelected, toBeDisabled, toBeEnabled, toBeVisible, toBeRooted, toBeEmpty, toBeInvalid, toBeValid, toBeRequired, toHaveFocus, toHaveValue, toHaveRole, toContainElement, toHaveClass, toHaveObjectProperty, matchers, registerMatchers, };
117
354
  //# sourceMappingURL=matchers.js.map