@bitforgehq/ui 0.4.0 → 0.5.0-next.3
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.
- package/CHANGELOG.md +303 -0
- package/README.md +12 -12
- package/ai/MANIFEST.index.json +65 -2
- package/ai/MANIFEST.json +2221 -737
- package/ai/REFERENCE.index.json +161 -0
- package/ai/REFERENCE.json +1336 -27
- package/ai/UI_GUIDE.md +61 -20
- package/ai/components/app-frame.md +1 -1
- package/ai/components/chat-composer.md +357 -0
- package/ai/components/chat-message.md +251 -0
- package/ai/components/chat-thread.md +521 -0
- package/ai/components/checkbox.md +7 -0
- package/ai/components/combobox.md +12 -0
- package/ai/components/date-input.md +9 -0
- package/ai/components/datetime-input.md +2 -0
- package/ai/components/field.md +10 -0
- package/ai/components/file-input.md +498 -0
- package/ai/components/header.md +1 -1
- package/ai/components/image-input.md +368 -0
- package/ai/components/image-viewer.md +309 -0
- package/ai/components/media-card.md +478 -0
- package/ai/components/menu-button.md +2 -0
- package/ai/components/menu.md +10 -0
- package/ai/components/multi-combobox.md +7 -0
- package/ai/components/nav-group.md +10 -3
- package/ai/components/nav-item.md +11 -2
- package/ai/components/number-input.md +2 -7
- package/ai/components/popover.md +13 -0
- package/ai/components/radio-group.md +6 -0
- package/ai/components/segmented.md +14 -2
- package/ai/components/select.md +100 -42
- package/ai/components/sidebar-toggle.md +16 -9
- package/ai/components/sidebar.md +41 -13
- package/ai/components/tab-group.md +18 -2
- package/ai/components/table.md +17 -2
- package/ai/components/theme-menu-button.md +1 -0
- package/ai/components/time-input.md +2 -0
- package/ai/components/toolbar.md +7 -18
- package/ai/reference/bf-chat-composer-harness.md +64 -0
- package/ai/reference/bf-chat-message-role.md +27 -0
- package/ai/reference/bf-chat-message-status.md +28 -0
- package/ai/reference/bf-fade-in-directive.md +18 -0
- package/ai/reference/bf-file-input-harness.md +67 -0
- package/ai/reference/bf-file-input-variant.md +27 -0
- package/ai/reference/bf-image-input-harness.md +67 -0
- package/ai/reference/bf-image-input-shape.md +27 -0
- package/ai/reference/bf-image-viewer-actions-context.md +29 -0
- package/ai/reference/bf-image-viewer-harness.md +87 -0
- package/ai/reference/bf-image-viewer-image.md +25 -0
- package/ai/reference/bf-image-viewer-options.md +33 -0
- package/ai/reference/bf-image-viewer-origin.md +23 -0
- package/ai/reference/bf-image-viewer-ref.md +55 -0
- package/ai/reference/bf-image-viewer-service.md +32 -0
- package/ai/reference/bf-labels.md +105 -75
- package/ai/reference/bf-media-card-aspect.md +28 -0
- package/ai/reference/bf-media-card-harness.md +66 -0
- package/ai/reference/bf-motion-list-directive.md +22 -0
- package/ai/reference/bf-prose-directive.md +16 -0
- package/ai/reference/bf-rejected-file-reason.md +28 -0
- package/ai/reference/bf-rejected-file.md +28 -0
- package/ai/reference/bf-select-harness.md +14 -5
- package/ai/reference/bf-select-option.md +2 -0
- package/ai/reference/bf-size.md +3 -0
- package/ai/reference/bf_table_sort_select.md +23 -0
- package/ai/reference/provide-bf-labels.md +10 -3
- package/ai/reference/provide-bf-select.md +20 -0
- package/bin/bf-ui.js +1 -0
- package/fesm2022/bitforgehq-ui-overlay.mjs +2649 -606
- package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui-testing.mjs +356 -10
- package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui.mjs +7531 -3989
- package/fesm2022/bitforgehq-ui.mjs.map +1 -1
- package/llms-full.txt +4151 -130
- package/llms.txt +31 -1
- package/package.json +1 -1
- package/theme.css +60 -0
- package/types/bitforgehq-ui-overlay.d.ts +684 -7
- package/types/bitforgehq-ui-testing.d.ts +434 -6
- package/types/bitforgehq-ui.d.ts +1473 -182
|
@@ -110,29 +110,44 @@ function provideBfTesting(options = {}) {
|
|
|
110
110
|
return makeEnvironmentProviders([...providers, ɵprovideBfDocumentReset()]);
|
|
111
111
|
}
|
|
112
112
|
var BfSelectHarness = class BfSelectHarness extends ComponentHarness {
|
|
113
|
-
static hostSelector = "bf-select";
|
|
114
|
-
|
|
113
|
+
static hostSelector = "bf-select, [data-bf-select]";
|
|
114
|
+
nativeSelect = this.locatorForOptional("select");
|
|
115
|
+
combobox = this.locatorForOptional("[role=\"combobox\"]");
|
|
115
116
|
label = this.locatorForOptional("label");
|
|
116
117
|
error = this.locatorForOptional("p[id$=\"-error\"]");
|
|
117
118
|
help = this.locatorForOptional("p[id$=\"-help\"]");
|
|
118
119
|
nativeOptions = this.locatorForAll("option");
|
|
120
|
+
styledOptions = this.locatorForAll("[data-bf-select-options] > span");
|
|
119
121
|
static with(filters = {}) {
|
|
120
122
|
return new HarnessPredicate(BfSelectHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
|
|
121
123
|
}
|
|
122
124
|
async getLabel() {
|
|
123
125
|
const label = await this.label();
|
|
124
126
|
if (label) return (await label.text({ exclude: "[aria-hidden=\"true\"]" })).trim();
|
|
125
|
-
return await (await this.
|
|
127
|
+
return await (await this.control()).getAttribute("aria-label") ?? "";
|
|
128
|
+
}
|
|
129
|
+
async isOpen() {
|
|
130
|
+
if (await this.nativeSelect()) return false;
|
|
131
|
+
return await (await this.control()).getAttribute("aria-expanded") === "true";
|
|
126
132
|
}
|
|
127
133
|
async getValueLabel() {
|
|
134
|
+
if (!await this.nativeSelect()) {
|
|
135
|
+
const field = await this.control();
|
|
136
|
+
return await field.getAttribute("data-placeholder") !== null ? "" : (await field.text()).trim();
|
|
137
|
+
}
|
|
128
138
|
for (const option of await this.options()) if (option.choice && await option.element.getProperty("selected")) return option.label;
|
|
129
139
|
return "";
|
|
130
140
|
}
|
|
131
141
|
async getOptionLabels() {
|
|
142
|
+
if (!await this.nativeSelect()) return (await this.styledChoices()).map((option) => option.label);
|
|
132
143
|
return (await this.options()).filter((option) => option.choice).map((option) => option.label);
|
|
133
144
|
}
|
|
134
145
|
async selectOption(label) {
|
|
135
146
|
if (await this.isDisabled()) throw new Error(`BfSelectHarness: the select is disabled, so "${label}" cannot be chosen`);
|
|
147
|
+
if (!await this.nativeSelect()) {
|
|
148
|
+
await this.selectStyled(label);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
136
151
|
const options = await this.options();
|
|
137
152
|
const option = options.find((o) => o.choice && o.label === label);
|
|
138
153
|
if (!option) {
|
|
@@ -140,18 +155,20 @@ var BfSelectHarness = class BfSelectHarness extends ComponentHarness {
|
|
|
140
155
|
throw new Error(`BfSelectHarness: no option "${label}" (options: ${known.join(", ")})`);
|
|
141
156
|
}
|
|
142
157
|
if (await option.element.getProperty("disabled")) throw new Error(`BfSelectHarness: the option "${label}" is disabled`);
|
|
143
|
-
const select = await this.
|
|
158
|
+
const select = await this.control();
|
|
144
159
|
await select.setInputValue(await option.element.getProperty("value"));
|
|
145
160
|
await select.dispatchEvent("change");
|
|
146
161
|
}
|
|
147
162
|
async isDisabled() {
|
|
148
|
-
return (await this.
|
|
163
|
+
if (!await this.nativeSelect()) return await (await this.control()).getAttribute("aria-disabled") === "true";
|
|
164
|
+
return (await this.control()).getProperty("disabled");
|
|
149
165
|
}
|
|
150
166
|
async isReadonly() {
|
|
151
|
-
return await (await this.
|
|
167
|
+
return await (await this.control()).getAttribute("aria-readonly") === "true";
|
|
152
168
|
}
|
|
153
169
|
async isRequired() {
|
|
154
|
-
return (await this.
|
|
170
|
+
if (!await this.nativeSelect()) return await (await this.control()).getAttribute("aria-required") === "true";
|
|
171
|
+
return (await this.control()).getProperty("required");
|
|
155
172
|
}
|
|
156
173
|
async getErrorText() {
|
|
157
174
|
return (await (await this.error())?.text())?.trim() ?? "";
|
|
@@ -160,10 +177,61 @@ var BfSelectHarness = class BfSelectHarness extends ComponentHarness {
|
|
|
160
177
|
return (await (await this.help())?.text())?.trim() ?? "";
|
|
161
178
|
}
|
|
162
179
|
async focus() {
|
|
163
|
-
await (await this.
|
|
180
|
+
await (await this.control()).focus();
|
|
164
181
|
}
|
|
165
182
|
async blur() {
|
|
166
|
-
await (await this.
|
|
183
|
+
await (await this.control()).blur();
|
|
184
|
+
}
|
|
185
|
+
async control() {
|
|
186
|
+
const native = await this.nativeSelect();
|
|
187
|
+
if (native) return native;
|
|
188
|
+
const field = await this.combobox();
|
|
189
|
+
if (!field) throw new Error("BfSelectHarness: found neither a native select nor a combobox field");
|
|
190
|
+
return field;
|
|
191
|
+
}
|
|
192
|
+
async open() {
|
|
193
|
+
if (!await this.isOpen()) await (await this.control()).click();
|
|
194
|
+
}
|
|
195
|
+
async close() {
|
|
196
|
+
if (await this.isOpen()) await (await this.control()).sendKeys(TestKey.ESCAPE);
|
|
197
|
+
}
|
|
198
|
+
async listOptions() {
|
|
199
|
+
const id = await (await this.control()).getAttribute("aria-controls");
|
|
200
|
+
if (!id) return [];
|
|
201
|
+
const root = this.documentRootLocatorFactory();
|
|
202
|
+
const [elements, labels] = await Promise.all([root.locatorForAll(`[id="${id}"] [role="option"]`)(), root.locatorForAll(`[id="${id}"] [role="option"] [data-label]`)()]);
|
|
203
|
+
return Promise.all(elements.map(async (element, i) => ({
|
|
204
|
+
element,
|
|
205
|
+
label: (await (labels[i] ?? element).text()).trim()
|
|
206
|
+
})));
|
|
207
|
+
}
|
|
208
|
+
async styledChoices() {
|
|
209
|
+
return Promise.all((await this.styledOptions()).map(async (element) => {
|
|
210
|
+
const [label, disabled] = await Promise.all([element.text(), element.getAttribute("data-disabled")]);
|
|
211
|
+
return {
|
|
212
|
+
label: label.trim(),
|
|
213
|
+
disabled: disabled !== null
|
|
214
|
+
};
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
async selectStyled(label) {
|
|
218
|
+
const choices = await this.styledChoices();
|
|
219
|
+
const choice = choices.find((o) => o.label === label);
|
|
220
|
+
if (!choice) {
|
|
221
|
+
const known = choices.map((o) => o.label);
|
|
222
|
+
throw new Error(`BfSelectHarness: no option "${label}" (options: ${known.join(", ")})`);
|
|
223
|
+
}
|
|
224
|
+
if (choice.disabled) throw new Error(`BfSelectHarness: the option "${label}" is disabled`);
|
|
225
|
+
if (await this.isReadonly()) return;
|
|
226
|
+
await this.open();
|
|
227
|
+
const option = (await this.listOptions()).find((o) => o.label === label);
|
|
228
|
+
if (!option) {
|
|
229
|
+
await this.close();
|
|
230
|
+
throw new Error(`BfSelectHarness: the open list has no option "${label}"`);
|
|
231
|
+
}
|
|
232
|
+
await option.element.click();
|
|
233
|
+
await new Promise((resolve) => setTimeout(resolve));
|
|
234
|
+
await this.forceStabilize();
|
|
167
235
|
}
|
|
168
236
|
async options() {
|
|
169
237
|
return Promise.all((await this.nativeOptions()).map(async (element, index) => {
|
|
@@ -1083,6 +1151,284 @@ var BfToggleHarness = class BfToggleHarness extends ComponentHarness {
|
|
|
1083
1151
|
return (await (await this.error())?.text())?.trim() ?? "";
|
|
1084
1152
|
}
|
|
1085
1153
|
};
|
|
1086
|
-
|
|
1154
|
+
var BfFileInputHarness = class BfFileInputHarness extends ComponentHarness {
|
|
1155
|
+
static hostSelector = "bf-file-input";
|
|
1156
|
+
label = this.locatorForOptional("label");
|
|
1157
|
+
error = this.locatorForOptional("p[id$=\"-error\"]");
|
|
1158
|
+
box = this.locatorForOptional("[data-box]");
|
|
1159
|
+
pick = this.locatorForOptional("[data-pick]");
|
|
1160
|
+
ariaLabelText = this.locatorForOptional("[data-aria-label]");
|
|
1161
|
+
dropzone = this.locatorForOptional("[data-dropzone]");
|
|
1162
|
+
nativeInput = this.locatorFor("input[type=\"file\"]");
|
|
1163
|
+
names = this.locatorForAll("[data-file] [data-name]");
|
|
1164
|
+
removeButtons = this.locatorForAll("[data-file] button");
|
|
1165
|
+
rejectedNames = this.locatorForAll("[data-rejected] [data-rejected-name]");
|
|
1166
|
+
rejectedMessages = this.locatorForAll("[data-rejected] [data-rejected-message]");
|
|
1167
|
+
static with(filters = {}) {
|
|
1168
|
+
return new HarnessPredicate(BfFileInputHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
|
|
1169
|
+
}
|
|
1170
|
+
async getLabel() {
|
|
1171
|
+
const label = await this.label();
|
|
1172
|
+
if (label) return (await label.text({ exclude: "[aria-hidden=\"true\"]" })).trim();
|
|
1173
|
+
return (await (await this.ariaLabelText())?.text())?.trim() ?? "";
|
|
1174
|
+
}
|
|
1175
|
+
async getErrorText() {
|
|
1176
|
+
return (await (await this.error())?.text())?.trim() ?? "";
|
|
1177
|
+
}
|
|
1178
|
+
async getVariant() {
|
|
1179
|
+
return await this.dropzone() !== null || await this.box() === null ? "dropzone" : "field";
|
|
1180
|
+
}
|
|
1181
|
+
async isDisabled() {
|
|
1182
|
+
return (await this.nativeInput()).getProperty("disabled");
|
|
1183
|
+
}
|
|
1184
|
+
async isReadonly() {
|
|
1185
|
+
return await this.pick() === null;
|
|
1186
|
+
}
|
|
1187
|
+
async addFiles(files) {
|
|
1188
|
+
const target = await this.box();
|
|
1189
|
+
if (!target || await this.isDisabled() || await this.isReadonly()) return;
|
|
1190
|
+
const data = { dataTransfer: { files } };
|
|
1191
|
+
await target.dispatchEvent("drop", data);
|
|
1192
|
+
}
|
|
1193
|
+
async getFileNames() {
|
|
1194
|
+
return Promise.all((await this.names()).map(async (name) => (await name.text()).trim()));
|
|
1195
|
+
}
|
|
1196
|
+
async getRejected() {
|
|
1197
|
+
const [names, messages] = await Promise.all([this.rejectedNames(), this.rejectedMessages()]);
|
|
1198
|
+
return Promise.all(names.map(async (name, index) => ({
|
|
1199
|
+
name: (await name.text()).trim(),
|
|
1200
|
+
message: (await messages[index]?.text() ?? "").trim()
|
|
1201
|
+
})));
|
|
1202
|
+
}
|
|
1203
|
+
async removeFile(name) {
|
|
1204
|
+
const index = (await this.getFileNames()).indexOf(name);
|
|
1205
|
+
if (index < 0) throw new Error(`BfFileInputHarness: no chosen file is named "${name}"`);
|
|
1206
|
+
const button = (await this.removeButtons())[index];
|
|
1207
|
+
if (!button) throw new Error(`BfFileInputHarness: "${name}" cannot be removed from this field`);
|
|
1208
|
+
await button.click();
|
|
1209
|
+
}
|
|
1210
|
+
};
|
|
1211
|
+
var BfImageInputHarness = class BfImageInputHarness extends ComponentHarness {
|
|
1212
|
+
static hostSelector = "bf-image-input";
|
|
1213
|
+
label = this.locatorForOptional("label");
|
|
1214
|
+
error = this.locatorForOptional("p[id$=\"-error\"]");
|
|
1215
|
+
tile = this.locatorFor("[data-tile]");
|
|
1216
|
+
preview = this.locatorForOptional("[data-tile] img");
|
|
1217
|
+
removeButton = this.locatorForOptional("[data-remove]");
|
|
1218
|
+
rejection = this.locatorForOptional("[data-rejection]");
|
|
1219
|
+
nativeInput = this.locatorFor("input[type=\"file\"]");
|
|
1220
|
+
static with(filters = {}) {
|
|
1221
|
+
return new HarnessPredicate(BfImageInputHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
|
|
1222
|
+
}
|
|
1223
|
+
async getLabel() {
|
|
1224
|
+
const label = await this.label();
|
|
1225
|
+
if (label) return (await label.text({ exclude: "[aria-hidden=\"true\"]" })).trim();
|
|
1226
|
+
return await (await this.tile()).getAttribute("aria-label") ?? "";
|
|
1227
|
+
}
|
|
1228
|
+
async getErrorText() {
|
|
1229
|
+
return (await (await this.error())?.text())?.trim() ?? "";
|
|
1230
|
+
}
|
|
1231
|
+
async isDisabled() {
|
|
1232
|
+
return (await this.nativeInput()).getProperty("disabled");
|
|
1233
|
+
}
|
|
1234
|
+
async isReadonly() {
|
|
1235
|
+
return await (await this.tile()).getProperty("tagName") !== "BUTTON";
|
|
1236
|
+
}
|
|
1237
|
+
async hasPreview() {
|
|
1238
|
+
return await this.preview() !== null;
|
|
1239
|
+
}
|
|
1240
|
+
async getPreviewSrc() {
|
|
1241
|
+
return (await this.preview())?.getAttribute("src") ?? null;
|
|
1242
|
+
}
|
|
1243
|
+
async addFile(file) {
|
|
1244
|
+
if (await this.isDisabled() || await this.isReadonly()) return;
|
|
1245
|
+
const data = { dataTransfer: { files: [file] } };
|
|
1246
|
+
await (await this.tile()).dispatchEvent("drop", data);
|
|
1247
|
+
}
|
|
1248
|
+
async remove() {
|
|
1249
|
+
const button = await this.removeButton();
|
|
1250
|
+
if (!button) throw new Error("BfImageInputHarness: there is no Remove button, so nothing can be removed");
|
|
1251
|
+
await button.click();
|
|
1252
|
+
}
|
|
1253
|
+
async getRejectedMessage() {
|
|
1254
|
+
return (await (await this.rejection())?.text())?.trim() ?? "";
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
var BfMediaCardHarness = class BfMediaCardHarness extends ComponentHarness {
|
|
1258
|
+
static hostSelector = "bf-media-card";
|
|
1259
|
+
media = this.locatorFor("[data-media]");
|
|
1260
|
+
image = this.locatorForOptional("[data-media] img");
|
|
1261
|
+
heading = this.locatorForOptional("[data-body] h1, [data-body] h2, [data-body] h3, [data-body] h4, [data-body] h5, [data-body] h6");
|
|
1262
|
+
loadingLabel = this.locatorForOptional("[data-loading-label]");
|
|
1263
|
+
failedLabel = this.locatorForOptional("[data-failed-label]");
|
|
1264
|
+
selectButton = this.locatorForOptional("button[data-select]");
|
|
1265
|
+
static with(filters = {}) {
|
|
1266
|
+
return new HarnessPredicate(BfMediaCardHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getTitle(), label));
|
|
1267
|
+
}
|
|
1268
|
+
async getTitle() {
|
|
1269
|
+
return (await (await this.heading())?.text())?.trim() ?? "";
|
|
1270
|
+
}
|
|
1271
|
+
async getState() {
|
|
1272
|
+
const state = await (await this.media()).getAttribute("data-state");
|
|
1273
|
+
return state === "loading" || state === "loaded" || state === "failed" ? state : "empty";
|
|
1274
|
+
}
|
|
1275
|
+
async getSrc() {
|
|
1276
|
+
return await (await this.image())?.getAttribute("src") ?? "";
|
|
1277
|
+
}
|
|
1278
|
+
async getAlt() {
|
|
1279
|
+
return await (await this.image())?.getAttribute("alt") ?? "";
|
|
1280
|
+
}
|
|
1281
|
+
async getLoadingLabel() {
|
|
1282
|
+
return (await (await this.loadingLabel())?.text())?.trim() ?? "";
|
|
1283
|
+
}
|
|
1284
|
+
async getFailedMessage() {
|
|
1285
|
+
return (await (await this.failedLabel())?.text())?.trim() ?? "";
|
|
1286
|
+
}
|
|
1287
|
+
async loadImage() {
|
|
1288
|
+
await (await this.requireImage()).dispatchEvent("load");
|
|
1289
|
+
}
|
|
1290
|
+
async failImage() {
|
|
1291
|
+
await (await this.requireImage()).dispatchEvent("error");
|
|
1292
|
+
}
|
|
1293
|
+
async isSelectable() {
|
|
1294
|
+
return await this.selectButton() !== null;
|
|
1295
|
+
}
|
|
1296
|
+
async isSelected() {
|
|
1297
|
+
return await (await this.selectButton())?.getAttribute("aria-pressed") === "true";
|
|
1298
|
+
}
|
|
1299
|
+
async toggleSelected() {
|
|
1300
|
+
const button = await this.selectButton();
|
|
1301
|
+
if (!button) throw new Error("BfMediaCardHarness: the card is not selectable");
|
|
1302
|
+
await button.click();
|
|
1303
|
+
}
|
|
1304
|
+
async requireImage() {
|
|
1305
|
+
const image = await this.image();
|
|
1306
|
+
if (!image) throw new Error("BfMediaCardHarness: the card shows no image (no src, or it failed)");
|
|
1307
|
+
return image;
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
var BfImageViewerHarness = class BfImageViewerHarness extends ComponentHarness {
|
|
1311
|
+
static hostSelector = "bf-image-viewer";
|
|
1312
|
+
image = this.locatorForOptional("img[data-image]");
|
|
1313
|
+
frame = this.locatorFor("[data-frame]");
|
|
1314
|
+
caption = this.locatorForOptional("[data-caption]");
|
|
1315
|
+
counter = this.locatorFor("[data-counter]");
|
|
1316
|
+
closeButton = this.locatorFor("[data-close] button");
|
|
1317
|
+
nextButton = this.locatorForOptional("[data-next] button");
|
|
1318
|
+
previousButton = this.locatorForOptional("[data-previous] button");
|
|
1319
|
+
static with(filters = {}) {
|
|
1320
|
+
return new HarnessPredicate(BfImageViewerHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
|
|
1321
|
+
}
|
|
1322
|
+
async getLabel() {
|
|
1323
|
+
return await (await this.host()).getAttribute("data-label") ?? "";
|
|
1324
|
+
}
|
|
1325
|
+
async getIndex() {
|
|
1326
|
+
return Number(await (await this.host()).getAttribute("data-index"));
|
|
1327
|
+
}
|
|
1328
|
+
async getCount() {
|
|
1329
|
+
return Number(await (await this.host()).getAttribute("data-count"));
|
|
1330
|
+
}
|
|
1331
|
+
async getCounterText() {
|
|
1332
|
+
return await this.getCount() < 2 ? "" : (await (await this.counter()).text()).trim();
|
|
1333
|
+
}
|
|
1334
|
+
async getSrc() {
|
|
1335
|
+
return await (await this.image())?.getAttribute("src") ?? "";
|
|
1336
|
+
}
|
|
1337
|
+
async getAlt() {
|
|
1338
|
+
return await (await this.image())?.getAttribute("alt") ?? "";
|
|
1339
|
+
}
|
|
1340
|
+
async getCaption() {
|
|
1341
|
+
return (await (await this.caption())?.text())?.trim() ?? "";
|
|
1342
|
+
}
|
|
1343
|
+
async isLoaded() {
|
|
1344
|
+
return await (await this.frame()).getAttribute("data-status") === "loaded";
|
|
1345
|
+
}
|
|
1346
|
+
async hasFailed() {
|
|
1347
|
+
return await (await this.frame()).getAttribute("data-status") === "error";
|
|
1348
|
+
}
|
|
1349
|
+
async loadImage() {
|
|
1350
|
+
await (await this.requireImage()).dispatchEvent("load");
|
|
1351
|
+
}
|
|
1352
|
+
async failImage() {
|
|
1353
|
+
await (await this.requireImage()).dispatchEvent("error");
|
|
1354
|
+
}
|
|
1355
|
+
async next() {
|
|
1356
|
+
const button = await this.nextButton();
|
|
1357
|
+
if (!button) throw new Error("BfImageViewerHarness: a viewer of one image has no next button");
|
|
1358
|
+
await button.click();
|
|
1359
|
+
}
|
|
1360
|
+
async previous() {
|
|
1361
|
+
const button = await this.previousButton();
|
|
1362
|
+
if (!button) throw new Error("BfImageViewerHarness: a viewer of one image has no previous button");
|
|
1363
|
+
await button.click();
|
|
1364
|
+
}
|
|
1365
|
+
async pressKey(key) {
|
|
1366
|
+
const keys = {
|
|
1367
|
+
ArrowLeft: TestKey.LEFT_ARROW,
|
|
1368
|
+
ArrowRight: TestKey.RIGHT_ARROW,
|
|
1369
|
+
Home: TestKey.HOME,
|
|
1370
|
+
End: TestKey.END,
|
|
1371
|
+
Escape: TestKey.ESCAPE
|
|
1372
|
+
};
|
|
1373
|
+
await (await this.closeButton()).sendKeys(keys[key]);
|
|
1374
|
+
}
|
|
1375
|
+
async close() {
|
|
1376
|
+
await (await this.closeButton()).click();
|
|
1377
|
+
}
|
|
1378
|
+
async requireImage() {
|
|
1379
|
+
const image = await this.image();
|
|
1380
|
+
if (!image) throw new Error("BfImageViewerHarness: the viewer shows no image (it failed to load)");
|
|
1381
|
+
return image;
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
var BfChatComposerHarness = class BfChatComposerHarness extends ComponentHarness {
|
|
1385
|
+
static hostSelector = "bf-chat-composer";
|
|
1386
|
+
textarea = this.locatorFor("textarea");
|
|
1387
|
+
label = this.locatorForOptional("label");
|
|
1388
|
+
button = this.locatorFor("button[data-action]");
|
|
1389
|
+
static with(filters = {}) {
|
|
1390
|
+
return new HarnessPredicate(BfChatComposerHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
|
|
1391
|
+
}
|
|
1392
|
+
async getLabel() {
|
|
1393
|
+
const label = await this.label();
|
|
1394
|
+
return (label ? (await label.text()).trim() : "") || (await (await this.textarea()).getAttribute("aria-label") ?? "");
|
|
1395
|
+
}
|
|
1396
|
+
async getValue() {
|
|
1397
|
+
return (await this.textarea()).getProperty("value");
|
|
1398
|
+
}
|
|
1399
|
+
async setValue(text) {
|
|
1400
|
+
const textarea = await this.textarea();
|
|
1401
|
+
await textarea.clear();
|
|
1402
|
+
if (text) {
|
|
1403
|
+
await textarea.setInputValue(text);
|
|
1404
|
+
await textarea.dispatchEvent("input");
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
async send() {
|
|
1408
|
+
if (await this.isRunning() || !await this.canAct()) return;
|
|
1409
|
+
await (await this.button()).click();
|
|
1410
|
+
}
|
|
1411
|
+
async pressEnter() {
|
|
1412
|
+
await (await this.textarea()).sendKeys(TestKey.ENTER);
|
|
1413
|
+
}
|
|
1414
|
+
async stop() {
|
|
1415
|
+
if (!await this.isRunning() || !await this.canAct()) return;
|
|
1416
|
+
await (await this.button()).click();
|
|
1417
|
+
}
|
|
1418
|
+
async isRunning() {
|
|
1419
|
+
return await (await this.button()).getAttribute("data-mode") === "stop";
|
|
1420
|
+
}
|
|
1421
|
+
async isDisabled() {
|
|
1422
|
+
return (await this.textarea()).getProperty("disabled");
|
|
1423
|
+
}
|
|
1424
|
+
async canAct() {
|
|
1425
|
+
const button = await this.button();
|
|
1426
|
+
return !await button.getProperty("disabled") && await button.getAttribute("aria-disabled") !== "true";
|
|
1427
|
+
}
|
|
1428
|
+
async getButtonLabel() {
|
|
1429
|
+
return (await (await this.button()).text()).trim();
|
|
1430
|
+
}
|
|
1431
|
+
};
|
|
1432
|
+
export { BfCalendarHarness, BfChartHarness, BfChatComposerHarness, BfComboboxHarness, BfDateInputHarness, BfDateTimeInputHarness, BfDesktopToastHarness, BfDialogHarness, BfFileInputHarness, BfImageInputHarness, BfImageViewerHarness, BfMediaCardHarness, BfMenuButtonHarness, BfMenuHarness, BfMenuItemHarness, BfPaginationHarness, BfPopoverHarness, BfRadioGroupHarness, BfSegmentedHarness, BfSelectHarness, BfSidePanelHarness, BfSidebarToggleHarness, BfTabGroupHarness, BfTableHarness, BfTimeInputHarness, BfToggleHarness, BfTooltipHarness, installBfJsdomShims, provideBfTesting };
|
|
1087
1433
|
|
|
1088
1434
|
//# sourceMappingURL=bitforgehq-ui-testing.mjs.map
|