зеркало из https://github.com/microsoft/fast.git
This commit is contained in:
Родитель
d9f4a6c246
Коммит
a4018373f2
|
@ -1,12 +1,20 @@
|
|||
{
|
||||
"extends": ["@microsoft/eslint-config-fast-dna", "prettier"],
|
||||
"extends": [
|
||||
"@microsoft/eslint-config-fast-dna",
|
||||
"prettier",
|
||||
"plugin:storybook/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/class-name-casing": "off",
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"error",
|
||||
{
|
||||
"selector": "typeLike",
|
||||
"format": ["UPPER_CASE", "camelCase", "PascalCase"],
|
||||
"format": [
|
||||
"UPPER_CASE",
|
||||
"camelCase",
|
||||
"PascalCase"
|
||||
],
|
||||
"leadingUnderscore": "allow"
|
||||
}
|
||||
],
|
||||
|
@ -24,13 +32,22 @@
|
|||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts"],
|
||||
"excludedFiles": ["**/*.stories.ts"],
|
||||
"files": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"excludedFiles": [
|
||||
"**/*.stories.ts",
|
||||
"**/__test__/**",
|
||||
"test/**"
|
||||
],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": ["**/stories/**", "**/*.pw.spec.ts"]
|
||||
"patterns": [
|
||||
"**/stories/**",
|
||||
"**/*.pw.spec.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
const ResolveTypescriptPlugin = require("resolve-typescript-plugin");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
|
||||
stories: ["../src/**/stories/*.stories.ts", "debug.stories.ts"],
|
||||
framework: "@storybook/html",
|
||||
features: {
|
||||
babelModeV7: true,
|
||||
},
|
||||
core: {
|
||||
disableTelemetry: true,
|
||||
builder: {
|
||||
name: "webpack5",
|
||||
options: {
|
||||
lazyCompilation: true,
|
||||
fsCache: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
webpackFinal: async config => {
|
||||
config.performance = {
|
||||
...(config.performance ?? {}),
|
||||
hints: false,
|
||||
};
|
||||
config.module.rules = [
|
||||
{
|
||||
test: /\.svg$/,
|
||||
loader: "svg-inline-loader",
|
||||
options: {
|
||||
removeSVGTagAttrs: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.ts$/,
|
||||
loader: "ts-loader",
|
||||
sideEffects: true,
|
||||
options: {
|
||||
configFile: path.resolve("./tsconfig.json"),
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
enforce: "pre",
|
||||
loader: require.resolve("source-map-loader"),
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
config.resolve.plugins = [
|
||||
...(config.resolve.plugins ?? []),
|
||||
new ResolveTypescriptPlugin({
|
||||
includeNodeModules: true,
|
||||
}),
|
||||
];
|
||||
return config;
|
||||
},
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
import type { StorybookConfig } from "@storybook/html-vite";
|
||||
import { dirname, join } from "path";
|
||||
import { mergeConfig } from "vite";
|
||||
|
||||
/**
|
||||
* This function is used to resolve the absolute path of a package.
|
||||
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
|
||||
*/
|
||||
function getAbsolutePath(value: string): any {
|
||||
return dirname(require.resolve(join(value, "package.json")));
|
||||
}
|
||||
const config: StorybookConfig = {
|
||||
core: { disableTelemetry: true },
|
||||
stories: ["../src/**/*.stories.ts"],
|
||||
docs: { autodocs: true },
|
||||
addons: [
|
||||
// getAbsolutePath("@storybook/addon-interactions"),
|
||||
getAbsolutePath("@storybook/addon-essentials"),
|
||||
],
|
||||
framework: {
|
||||
name: getAbsolutePath("@storybook/html-vite"),
|
||||
options: {},
|
||||
},
|
||||
async viteFinal(config) {
|
||||
// Merge custom configuration into the default config
|
||||
return mergeConfig(config, {
|
||||
resolve: {
|
||||
alias: [{ find: /^(.*\.svg)$/, replacement: "$1?raw" }],
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
export default config;
|
|
@ -1,5 +0,0 @@
|
|||
import { addons } from "@storybook/addons";
|
||||
|
||||
addons.setConfig({
|
||||
enableShortcuts: false,
|
||||
});
|
|
@ -1,24 +1,31 @@
|
|||
<svg style="display: none;">
|
||||
<symbol
|
||||
id="test-icon"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg style="display: none">
|
||||
<symbol id="test-icon" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 5.5a1 1 0 100 2 1 1 0 000-2zm-5 1a1 1 0 112 0 1 1 0 01-2 0zm3.5-4a.5.5 0 00-1 0V3h-3C5.67 3 5 3.67 5 4.5v4c0 .83.67 1.5 1.5 1.5h7c.83 0 1.5-.67 1.5-1.5v-4c0-.83-.67-1.5-1.5-1.5h-3v-.5zM6.5 4h7c.28 0 .5.22.5.5v4a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-4c0-.28.22-.5.5-.5zm3.75 14c2.62-.04 4.2-.6 5.12-1.44A3.52 3.52 0 0016.5 14h.01v-.69c0-1-.81-1.8-1.8-1.8h-3.2v-.01H5.3c-.99 0-1.8.81-1.8 1.81v.7c.04.77.25 1.75 1.13 2.55.93.84 2.5 1.4 5.12 1.44h.5zm-4.94-5.5h9.38c.45 0 .81.37.81.81v.44c0 .69-.13 1.46-.8 2.07C14 16.45 12.66 17 10 17s-4.01-.55-4.7-1.18a2.63 2.63 0 01-.8-2.07v-.44c0-.44.36-.8.8-.8z"
|
||||
/>
|
||||
</symbol>
|
||||
<symbol
|
||||
id="test-icon-2"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<symbol id="test-icon-2" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M8.26 4.6a5.21 5.21 0 0 1 9.03 5.22l-.2.34a.5.5 0 0 1-.67.19l-3.47-2-1.93 3.38c1.34.4 2.5 1.33 3.31 2.52h-.09c-.34 0-.66.11-.92.31A4.9 4.9 0 0 0 9.5 12.5a4.9 4.9 0 0 0-3.82 2.06 1.5 1.5 0 0 0-1.01-.3 5.94 5.94 0 0 1 5.31-2.74l2.1-3.68-3.83-2.2a.5.5 0 0 1-.18-.7l.2-.33Zm.92.42 1.7.98.02-.02a8.08 8.08 0 0 1 3.27-2.74 4.22 4.22 0 0 0-4.99 1.78ZM14 7.8c.47-.82.7-1.46.77-2.09a5.8 5.8 0 0 0-.06-1.62 6.96 6.96 0 0 0-2.95 2.41L14 7.8Zm.87.5 1.61.93a4.22 4.22 0 0 0-.74-5.02c.07.56.09 1.1.02 1.63-.1.79-.38 1.56-.89 2.46Zm-9.63 7.3a.5.5 0 0 0-.96.03c-.17.7-.5 1.08-.86 1.3-.38.23-.87.32-1.42.32a.5.5 0 0 0 0 1c.64 0 1.33-.1 1.94-.47.34-.2.64-.5.88-.87a2.96 2.96 0 0 0 4.68-.01 2.96 2.96 0 0 0 4.74-.06c.64.9 1.7 1.41 2.76 1.41a.5.5 0 1 0 0-1c-.98 0-1.96-.64-2.29-1.65a.5.5 0 0 0-.95 0 1.98 1.98 0 0 1-3.79.07.5.5 0 0 0-.94 0 1.98 1.98 0 0 1-3.8-.08Z"
|
||||
/>
|
||||
</symbol>
|
||||
|
||||
<symbol
|
||||
id="chevron-up-12-regular"
|
||||
viewBox="0 0 12 12"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2.15 7.35c.2.2.5.2.7 0L6 4.21l3.15 3.14a.5.5 0 1 0 .7-.7l-3.5-3.5a.5.5 0 0 0-.7 0l-3.5 3.5a.5.5 0 0 0 0 .7Z"
|
||||
/>
|
||||
</symbol>
|
||||
<symbol
|
||||
id="chevron-down-12-regular"
|
||||
viewBox="0 0 12 12"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M9.85 4.65a.5.5 0 0 0-.7 0L6 7.79 2.85 4.65a.5.5 0 0 0-.7.7l3.5 3.5a.5.5 0 0 0 .7 0l3.5-3.5a.5.5 0 0 0 0-.7Z"
|
||||
/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 1.8 KiB После Ширина: | Высота: | Размер: 2.3 KiB |
|
@ -0,0 +1,90 @@
|
|||
import { useArgs } from "@storybook/client-api";
|
||||
import type { Preview } from "@storybook/html";
|
||||
|
||||
import customElements from "../dist/custom-elements.json";
|
||||
global["__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__"] = customElements;
|
||||
|
||||
import "@microsoft/fast-element";
|
||||
|
||||
import "../src/anchor/stories/anchor.register.js";
|
||||
import "../src/anchored-region/stories/anchored-region.register.js";
|
||||
import "../src/avatar/stories/avatar.register.js";
|
||||
import "../src/badge/stories/badge.register.js";
|
||||
import "../src/button/stories/button.register.js";
|
||||
import "../src/card/stories/card.register.js";
|
||||
import "../src/checkbox/stories/checkbox.register.js";
|
||||
import "../src/dialog/stories/dialog.register.js";
|
||||
import "../src/disclosure/stories/disclosure.register.js";
|
||||
import "../src/divider/stories/divider.register.js";
|
||||
import "../src/flipper/stories/flipper.register.js";
|
||||
import "../src/form-associated/stories/form-associated.register.js";
|
||||
import "../src/number-field/stories/number-field.register.js";
|
||||
import "../src/picker/stories/picker.register.js";
|
||||
import "../src/progress-ring/stories/progress-ring.register.js";
|
||||
import "../src/progress/stories/progress.register.js";
|
||||
import "../src/radio/stories/radio.register.js";
|
||||
import "../src/search/stories/search.register.js";
|
||||
import "../src/skeleton/stories/skeleton.register.js";
|
||||
import "../src/switch/stories/switch.register.js";
|
||||
import "../src/text-area/stories/text-area.register.js";
|
||||
import "../src/text-field/stories/text-field.register.js";
|
||||
import "../src/tooltip/stories/tooltip.register.js";
|
||||
|
||||
import "../src/data-grid/stories/data-grid-cell.register.js";
|
||||
import "../src/data-grid/stories/data-grid-row.register.js";
|
||||
import "../src/data-grid/stories/data-grid.register.js";
|
||||
|
||||
import "../src/calendar/stories/calendar.register.js";
|
||||
|
||||
import "../src/slider-label/stories/slider-label.register.js";
|
||||
import "../src/slider/stories/slider.register.js";
|
||||
|
||||
import "../src/accordion-item/stories/accordion-item.register.js";
|
||||
import "../src/accordion/stories/accordion.register.js";
|
||||
|
||||
import "../src/breadcrumb-item/stories/breadcrumb-item.register.js";
|
||||
import "../src/breadcrumb/stories/breadcrumb.register.js";
|
||||
|
||||
import "../src/listbox-option/stories/listbox-option.register.js";
|
||||
|
||||
import "../src/combobox/stories/combobox.register.js";
|
||||
import "../src/listbox/stories/listbox.register.js";
|
||||
import "../src/select/stories/select.register.js";
|
||||
|
||||
import "../src/tab-panel/stories/tab-panel.register.js";
|
||||
import "../src/tab/stories/tab.register.js";
|
||||
import "../src/tabs/stories/tabs.register.js";
|
||||
|
||||
import "../src/horizontal-scroll/stories/horizontal-scroll.register.js";
|
||||
import "../src/radio-group/stories/radio-group.register.js";
|
||||
import "../src/toolbar/stories/toolbar.register.js";
|
||||
|
||||
import "../src/menu-item/stories/menu-item.register.js";
|
||||
import "../src/menu/stories/menu.register.js";
|
||||
|
||||
import "../src/tree-item/stories/tree-item.register.js";
|
||||
import "../src/tree-view/stories/tree-view.register.js";
|
||||
|
||||
import { FAST, html } from "@microsoft/fast-element";
|
||||
|
||||
FAST["html"] = html;
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^.*Handler" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
(Story, context) => {
|
||||
const [_, updateArgs] = useArgs();
|
||||
return Story({ ...context, updateArgs });
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default preview;
|
|
@ -12,7 +12,7 @@ export default {
|
|||
"src/**/*.md",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/index.ts",
|
||||
"src/**/stories/*",
|
||||
"src/**/stories/*"
|
||||
],
|
||||
/** Directory to output CEM to */
|
||||
outdir: "dist",
|
||||
|
|
|
@ -412,7 +412,7 @@ export const DayFormat: {
|
|||
// @public
|
||||
export type DayFormat = ValuesOf<typeof DayFormat>;
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const defaultCellFocusTargetCallback: (cell: FASTDataGridCell) => HTMLElement | null;
|
||||
|
||||
// Warning: (ae-different-release-tags) This symbol has another declaration with a different release tag
|
||||
|
@ -2067,6 +2067,9 @@ export class FASTTextField extends FormAssociatedTextField {
|
|||
size: number;
|
||||
// (undocumented)
|
||||
protected sizeChanged(): void;
|
||||
slottedDataList?: HTMLDataListElement[];
|
||||
// (undocumented)
|
||||
protected slottedDataListChanged(prev: HTMLDataListElement[] | undefined, next: HTMLDataListElement[] | undefined): void;
|
||||
spellcheck: boolean;
|
||||
// (undocumented)
|
||||
protected spellcheckChanged(): void;
|
||||
|
@ -2870,9 +2873,9 @@ export type YearFormat = ValuesOf<typeof YearFormat>;
|
|||
|
||||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// dist/dts/calendar/calendar.d.ts:51:5 - (ae-incompatible-release-tags) The symbol "dataGridCell" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/calendar/calendar.d.ts:52:5 - (ae-incompatible-release-tags) The symbol "dataGridRow" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/calendar/calendar.d.ts:53:5 - (ae-incompatible-release-tags) The symbol "dataGrid" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/calendar/calendar.d.ts:52:5 - (ae-incompatible-release-tags) The symbol "dataGridCell" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/calendar/calendar.d.ts:53:5 - (ae-incompatible-release-tags) The symbol "dataGridRow" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/calendar/calendar.d.ts:54:5 - (ae-incompatible-release-tags) The symbol "dataGrid" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/data-grid/data-grid-row.template.d.ts:9:5 - (ae-incompatible-release-tags) The symbol "dataGridCell" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/data-grid/data-grid.template.d.ts:9:5 - (ae-incompatible-release-tags) The symbol "dataGridRow" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
// dist/dts/picker/picker.template.d.ts:9:5 - (ae-incompatible-release-tags) The symbol "anchoredRegion" is marked as @public, but its signature references "TemplateElementDependency" which is marked as @beta
|
||||
|
|
|
@ -226,7 +226,7 @@
|
|||
"doc": "api-extractor run --local",
|
||||
"doc:ci": "api-extractor run",
|
||||
"build:rollup": "rollup -c",
|
||||
"build:storybook": "build-storybook",
|
||||
"build:storybook": "storybook build",
|
||||
"build:tsc": "tsc -p ./tsconfig.build.json",
|
||||
"prebuild": "yarn build:tsc",
|
||||
"build": "yarn build:rollup",
|
||||
|
@ -242,11 +242,14 @@
|
|||
"prettier:diff": "prettier --config ../../../.prettierrc \"**/*.ts\" --list-different",
|
||||
"eslint": "eslint . --ext .ts",
|
||||
"eslint:fix": "eslint . --ext .ts --fix",
|
||||
"pretest": "yarn eslint && yarn build-storybook --quiet",
|
||||
"pretest": "yarn eslint",
|
||||
"test": "playwright test",
|
||||
"posttest:ci": "yarn doc:ci",
|
||||
"start": "yarn start:storybook",
|
||||
"start:storybook": "start-storybook -p 6006"
|
||||
"test:dev": "node test/server.js",
|
||||
"watch:dev": "concurrently \"yarn:test:dev\" \"yarn:watch:rollup\"",
|
||||
"watch:rollup": "rollup -c -w --waitForBundleInput",
|
||||
"start:storybook": "storybook dev -p 6006"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@custom-elements-manifest/analyzer": "^0.5.7",
|
||||
|
@ -255,35 +258,41 @@
|
|||
"@microsoft/tsdoc-config": "^0.13.4",
|
||||
"@playwright/test": "^1.25.2",
|
||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||
"@storybook/addon-docs": "6.5.10",
|
||||
"@storybook/addon-essentials": "6.5.10",
|
||||
"@storybook/addon-links": "6.5.10",
|
||||
"@storybook/builder-webpack5": "6.5.10",
|
||||
"@storybook/csf": "0.0.2--canary.0899bb7.0",
|
||||
"@storybook/html": "6.5.10",
|
||||
"@storybook/manager-webpack5": "6.5.10",
|
||||
"concurrently": "^7.3.0",
|
||||
"@storybook/addon-essentials": "^7.6.8",
|
||||
"@storybook/addon-interactions": "^7.6.8",
|
||||
"@storybook/addon-links": "^7.6.8",
|
||||
"@storybook/blocks": "^7.6.8",
|
||||
"@storybook/html": "^7.6.8",
|
||||
"@storybook/html-vite": "^7.6.8",
|
||||
"@storybook/test": "^7.6.8",
|
||||
"concurrently": "^8.2.2",
|
||||
"eslint-plugin-storybook": "^0.6.15",
|
||||
"esm": "^3.2.25",
|
||||
"express": "^4.18.1",
|
||||
"expect": "29.2.1",
|
||||
"express": "^4.18.1",
|
||||
"prettier": "2.8.8",
|
||||
"qs": "^6.11.0",
|
||||
"qs": "^6.11.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"resolve-typescript-plugin": "^1.2.0",
|
||||
"rollup-plugin-filesize": "^9.1.2",
|
||||
"rollup": "^4.9.1",
|
||||
"rollup-plugin-filesize": "^10.0.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"rollup-plugin-transform-tagged-template": "^0.0.3",
|
||||
"rollup": "^2.71.1",
|
||||
"source-map": "^0.7.4",
|
||||
"source-map-loader": "^0.2.4",
|
||||
"source-map": "^0.7.3",
|
||||
"storybook": "^7.6.8",
|
||||
"svg-inline-loader": "^0.8.2",
|
||||
"rollup-plugin-inline-svg": "^3.0.3",
|
||||
"@rollup/plugin-typescript": "^11.1.5",
|
||||
"ts-loader": "^7.0.2",
|
||||
"ts-node": "^8.9.1",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"typescript": "^4.7.0",
|
||||
"vite": "^5.0.10",
|
||||
"wait-on": "^6.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.0.3",
|
||||
"@floating-ui/dom": "1.0.3",
|
||||
"@microsoft/fast-element": "2.0.0-beta.26",
|
||||
"@microsoft/fast-web-utilities": "^6.0.0",
|
||||
"tabbable": "^5.2.0",
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import type { Locator, PlaywrightTestConfig } from "@playwright/test";
|
||||
import { expect } from "@playwright/test";
|
||||
|
||||
const isCI = !!process.env.CI;
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
projects: [{ name: "chromium" }, { name: "firefox" }, { name: "webkit" }],
|
||||
projects: [{ name: "chromium" }],
|
||||
reporter: "list",
|
||||
testMatch: /.*\.pw\.spec\.ts$/,
|
||||
retries: 3,
|
||||
fullyParallel: process.env.CI ? false : true,
|
||||
timeout: process.env.CI ? 10000 : 30000,
|
||||
fullyParallel: !isCI,
|
||||
timeout: isCI ? 10000 : 30000,
|
||||
use: {
|
||||
baseURL: "http://localhost:6006/iframe.html",
|
||||
baseURL: "http://localhost:6006/",
|
||||
viewport: {
|
||||
height: 1280,
|
||||
width: 720,
|
||||
},
|
||||
},
|
||||
webServer: {
|
||||
// double-quotes are required for Windows
|
||||
command: `node -e "import('express').then(({ default: e }) => e().use(e.static('./storybook-static')).listen(6006))"`,
|
||||
port: 6006,
|
||||
reuseExistingServer: process.env.CI ? false : true,
|
||||
command: "node test/server.js",
|
||||
port: 6007,
|
||||
reuseExistingServer: !isCI,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,28 +1,11 @@
|
|||
import filesize from "rollup-plugin-filesize";
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
||||
import filesize from "rollup-plugin-filesize";
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
import transformTaggedTemplate from "rollup-plugin-transform-tagged-template";
|
||||
import {
|
||||
transformCSSFragment,
|
||||
transformHTMLFragment,
|
||||
} from "../../../build/transform-fragments.js";
|
||||
|
||||
const parserOptions = {
|
||||
sourceType: "module",
|
||||
};
|
||||
import inlineSvg from "rollup-plugin-inline-svg";
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
|
||||
const plugins = [
|
||||
nodeResolve(),
|
||||
transformTaggedTemplate({
|
||||
tagsToProcess: ["css"],
|
||||
transformer: transformCSSFragment,
|
||||
parserOptions,
|
||||
}),
|
||||
transformTaggedTemplate({
|
||||
tagsToProcess: ["child", "html", "item"],
|
||||
transformer: transformHTMLFragment,
|
||||
parserOptions,
|
||||
}),
|
||||
filesize({
|
||||
showMinifiedSize: false,
|
||||
showBrotliSize: true,
|
||||
|
@ -60,4 +43,19 @@ export default [
|
|||
],
|
||||
plugins,
|
||||
},
|
||||
{
|
||||
input: "test/bundle.ts",
|
||||
output: {
|
||||
file: "test/public/dist/bundle.js",
|
||||
format: "cjs",
|
||||
},
|
||||
context: "window",
|
||||
plugins: [
|
||||
nodeResolve(),
|
||||
inlineSvg(),
|
||||
typescript({
|
||||
tsconfig: "./tsconfig.test.json",
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
|
@ -8,8 +8,3 @@ declare global {
|
|||
}
|
||||
|
||||
export {};
|
||||
|
||||
declare module "*.svg" {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
|
|
|
@ -4,42 +4,9 @@ import type {
|
|||
Args,
|
||||
ComponentAnnotations,
|
||||
StoryAnnotations,
|
||||
StoryContext,
|
||||
StoryContext
|
||||
} from "@storybook/csf";
|
||||
import qs from "qs";
|
||||
|
||||
/**
|
||||
* Returns a formatted URL for a given Storybook fixture.
|
||||
*
|
||||
* @param id - the Storybook fixture ID
|
||||
* @param args - Story args
|
||||
* @returns - the local URL for the Storybook fixture iframe
|
||||
*/
|
||||
export function fixtureURL(
|
||||
id: string = "debug--blank",
|
||||
args?: Record<string, any>
|
||||
): string {
|
||||
const params: Record<string, any> = { id };
|
||||
if (args) {
|
||||
params.args = qs
|
||||
.stringify(args, {
|
||||
allowDots: true,
|
||||
delimiter: ";",
|
||||
format: "RFC1738",
|
||||
encode: false,
|
||||
})
|
||||
.replace(/=/g, ":")
|
||||
.replace(/\//g, "--");
|
||||
}
|
||||
|
||||
const url = qs.stringify(params, {
|
||||
addQueryPrefix: true,
|
||||
format: "RFC1738",
|
||||
encode: false,
|
||||
});
|
||||
|
||||
return url;
|
||||
}
|
||||
import type { HtmlRenderer } from "@storybook/html";
|
||||
|
||||
/**
|
||||
* A helper that returns a function to bind a Storybook story to a ViewTemplate.
|
||||
|
@ -63,23 +30,23 @@ export function renderComponent<TArgs = Args>(
|
|||
/**
|
||||
* A helper that returns a function to bind a Storybook story to a ViewTemplate.
|
||||
*/
|
||||
export type FASTFramework = {
|
||||
component: typeof FASTElement;
|
||||
storyResult: FASTElement | Element | DocumentFragment;
|
||||
export type FASTFramework = HtmlRenderer & {
|
||||
component: string;
|
||||
storyResult: HtmlRenderer["storyResult"] | FASTElement;
|
||||
};
|
||||
|
||||
/**
|
||||
* Metadata to configure the stories for a component.
|
||||
*/
|
||||
export type Meta<TArgs = Args> = ComponentAnnotations<
|
||||
export type Meta<TArgs extends Args = Args> = ComponentAnnotations<
|
||||
FASTFramework,
|
||||
Omit<TArgs, keyof FASTElement>
|
||||
Omit<TArgs, keyof FASTElement> & Args
|
||||
>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
*/
|
||||
export declare type StoryObj<TArgs = Args> = StoryAnnotations<FASTFramework, TArgs>;
|
||||
export declare type StoryObj<TArgs extends Args = Args> = StoryAnnotations<FASTFramework, TArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv2 component example.
|
||||
|
@ -91,7 +58,7 @@ export declare type StoryFn<TArgs = Args> = AnnotatedStoryFn<FASTFramework, TArg
|
|||
*
|
||||
* NOTE that in Storybook 7.0, this type will be renamed to `StoryFn` and replaced by the current `StoryObj` type.
|
||||
*/
|
||||
export declare type Story<TArgs = Args> = StoryFn<StoryArgs<TArgs>>;
|
||||
export declare type Story<TArgs = Args> = StoryObj<StoryArgs<TArgs>>;
|
||||
|
||||
/**
|
||||
* Combined Storybook story args.
|
||||
|
|
|
@ -1,35 +1,15 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTAccordionItem } from "./accordion-item.js";
|
||||
|
||||
test.describe("Accordion item", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let heading: Locator;
|
||||
let button: Locator;
|
||||
test("should set a default heading level of 2 when `headinglevel` is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-accordion-item");
|
||||
|
||||
element = page.locator("fast-accordion-item");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
heading = page.locator(`[role="heading"]`);
|
||||
|
||||
button = element.locator("button");
|
||||
|
||||
await page.goto(fixtureURL("accordion-item--accordion-item"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set a default heading level of 2 when `headinglevel` is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion-item>
|
||||
<span slot="heading">Heading 1</span>
|
||||
|
@ -43,8 +23,16 @@ test.describe("Accordion item", () => {
|
|||
await expect(element).toHaveJSProperty("headinglevel", 2);
|
||||
});
|
||||
|
||||
test("should set the `aria-level` attribute on the internal heading element equal to the heading level", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-level` attribute on the internal heading element equal to the heading level", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-accordion-item");
|
||||
|
||||
const heading = element.locator(`[role="heading"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion-item>
|
||||
<span slot="heading">Heading 1</span>
|
||||
|
@ -60,8 +48,16 @@ test.describe("Accordion item", () => {
|
|||
await expect(heading).toHaveAttribute("aria-level", "3");
|
||||
});
|
||||
|
||||
test("should set `aria-expanded` property on the internal control equal to the `expanded` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `aria-expanded` property on the internal control equal to the `expanded` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-accordion-item");
|
||||
|
||||
const button = element.locator("button");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion-item expanded></fast-accordion-item>
|
||||
`;
|
||||
|
@ -76,8 +72,16 @@ test.describe("Accordion item", () => {
|
|||
await expect(button).toHaveAttribute("aria-expanded", "false");
|
||||
});
|
||||
|
||||
test("should set `disabled` attribute on the internal control equal to the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `disabled` attribute on the internal control equal to the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-accordion-item");
|
||||
|
||||
const button = element.locator("button");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion-item disabled></fast-accordion-item>
|
||||
`;
|
||||
|
@ -92,8 +96,16 @@ test.describe("Accordion item", () => {
|
|||
await expect(button).not.toHaveBooleanAttribute("disabled");
|
||||
});
|
||||
|
||||
test("should set internal properties to match the id when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set internal properties to match the id when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-accordion-item");
|
||||
|
||||
const button = element.locator("button");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion-item id="foo"></fast-accordion-item>
|
||||
`;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { html } from "@microsoft/fast-element";
|
||||
import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js";
|
||||
import type { Meta } from "@storybook/html";
|
||||
import type { Story, StoryArgs } from "../../__test__/helpers.js";
|
||||
import { renderComponent } from "../../__test__/helpers.js";
|
||||
import type { FASTAccordionItem } from "../accordion-item.js";
|
||||
|
||||
|
@ -13,18 +14,20 @@ const storyTemplate = html<StoryArgs<FASTAccordionItem>>`
|
|||
</fast-accordion-item>
|
||||
`;
|
||||
|
||||
export default {
|
||||
const meta: Meta = {
|
||||
title: "Accordion Item",
|
||||
args: {
|
||||
expanded: false,
|
||||
},
|
||||
component: "FASTAccordionItem",
|
||||
parameters: { actions: { argTypesRegex: "^.*Handler" } },
|
||||
argTypes: {
|
||||
expanded: { control: "boolean" },
|
||||
headinglevel: { control: { type: "number", max: 6, min: 1 } },
|
||||
id: { control: "text" },
|
||||
storyContent: { table: { disable: true } },
|
||||
clickHandler: { action: "click" },
|
||||
},
|
||||
} as Meta<FASTAccordionItem>;
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const AccordionItem: Story<FASTAccordionItem> = renderComponent(
|
||||
storyTemplate
|
||||
|
|
|
@ -1,30 +1,17 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import { AccordionExpandMode } from "./accordion.options.js";
|
||||
import type { FASTAccordion } from "./accordion.js";
|
||||
|
||||
test.describe("Accordion", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
// test.beforeEach(async ({ page }) => {
|
||||
// // await page.goto();
|
||||
// });
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
test("should set an expand mode of `multi` when passed to the `expand-mode` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
element = page.locator("fast-accordion");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("accordion--accordion"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set an expand mode of `multi` when passed to the `expand-mode` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="multi">
|
||||
<fast-accordion-item>
|
||||
|
@ -42,8 +29,12 @@ test.describe("Accordion", () => {
|
|||
await expect(element).toHaveAttribute("expand-mode", AccordionExpandMode.multi);
|
||||
});
|
||||
|
||||
test("should set an expand mode of `single` when passed to the `expand-mode` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set an expand mode of `single` when passed to the `expand-mode` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -61,8 +52,12 @@ test.describe("Accordion", () => {
|
|||
await expect(element).toHaveAttribute("expand-mode", AccordionExpandMode.single);
|
||||
});
|
||||
|
||||
test("should set a default expand mode of `multi` when `expand-mode` attribute is not passed", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default expand mode of `multi` when `expand-mode` attribute is not passed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion>
|
||||
<fast-accordion-item>
|
||||
|
@ -82,8 +77,10 @@ test.describe("Accordion", () => {
|
|||
await expect(element).toHaveAttribute("expand-mode", AccordionExpandMode.multi);
|
||||
});
|
||||
|
||||
test("should expand/collapse items when clicked in multi mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should expand/collapse items when clicked in multi mode", async ({ page }) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="multi">
|
||||
<fast-accordion-item>
|
||||
|
@ -109,8 +106,10 @@ test.describe("Accordion", () => {
|
|||
await expect(items.nth(1)).toHaveAttribute("expanded", "");
|
||||
});
|
||||
|
||||
test("should only have one expanded item in single mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should only have one expanded item in single mode", async ({ page }) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -150,8 +149,12 @@ test.describe("Accordion", () => {
|
|||
await expect(secondItem).toHaveBooleanAttribute("expanded");
|
||||
});
|
||||
|
||||
test("should set the expanded items' button to aria-disabled when in single expand mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the expanded items' button to aria-disabled when in single expand mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -202,8 +205,12 @@ test.describe("Accordion", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should remove an expanded items' expandbutton aria-disabled attribute when expand mode changes from single to multi", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should remove an expanded items' expandbutton aria-disabled attribute when expand mode changes from single to multi", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -238,8 +245,12 @@ test.describe("Accordion", () => {
|
|||
await expect(firstItem.locator("button")).not.hasAttribute("aria-disabled");
|
||||
});
|
||||
|
||||
test("should set the first item as expanded if no child is expanded by default in single mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the first item as expanded if no child is expanded by default in single mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -271,8 +282,12 @@ test.describe("Accordion", () => {
|
|||
await expect(secondItem).toHaveBooleanAttribute("expanded");
|
||||
});
|
||||
|
||||
test("should set the first item with an expanded attribute to expanded in single mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the first item with an expanded attribute to expanded in single mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -306,9 +321,14 @@ test.describe("Accordion", () => {
|
|||
await expect(thirdItem).not.toHaveBooleanAttribute("expanded");
|
||||
});
|
||||
|
||||
test("should allow disabled items to be expanded when in single mode", async () => {
|
||||
test("should allow disabled items to be expanded when in single mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
test.slow();
|
||||
await root.evaluate(node => {
|
||||
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
@ -352,8 +372,12 @@ test.describe("Accordion", () => {
|
|||
await expect(thirdItem).not.toHaveBooleanAttribute("expanded");
|
||||
});
|
||||
|
||||
test("should ignore `change` events from components other than accordion items", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should ignore `change` events from components other than accordion items", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-accordion");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-accordion expand-mode="single">
|
||||
<fast-accordion-item>
|
||||
|
|
|
@ -6,7 +6,7 @@ const styles = css`
|
|||
:host {
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
font: var(--type-ramp-minus1-font-size) / var(--type-ramp-minus1-line-height)
|
||||
font: var(--type-ramp-minus-1-font-size) / var(--type-ramp-minus1-line-height)
|
||||
var(--body-font);
|
||||
color: var(--neutral-foreground-rest);
|
||||
border-top: calc(var(--stroke-width) * 1px) solid
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { html } from "@microsoft/fast-element";
|
||||
import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js";
|
||||
import { renderComponent } from "../../__test__/helpers.js";
|
||||
import { FASTAccordion } from "../accordion.js";
|
||||
import type { FASTAccordion } from "../accordion.js";
|
||||
import { AccordionExpandMode } from "../accordion.options.js";
|
||||
|
||||
const storyTemplate = html<StoryArgs<FASTAccordion>>`
|
||||
|
@ -10,9 +10,9 @@ const storyTemplate = html<StoryArgs<FASTAccordion>>`
|
|||
</fast-accordion>
|
||||
`;
|
||||
|
||||
export default {
|
||||
const meta: Meta<FASTAccordion> = {
|
||||
title: "Accordion",
|
||||
component: FASTAccordion,
|
||||
component: "anchor",
|
||||
args: {
|
||||
expandmode: AccordionExpandMode.multi,
|
||||
},
|
||||
|
@ -20,7 +20,9 @@ export default {
|
|||
expandmode: { control: "select", options: Object.values(AccordionExpandMode) },
|
||||
storyContent: { table: { disable: true } },
|
||||
},
|
||||
} as Meta<FASTAccordion>;
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Accordion: Story<FASTAccordion> = renderComponent(storyTemplate).bind({});
|
||||
Accordion.args = {
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
|
||||
test.describe("Anchor", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
|
||||
element = page.locator("fast-anchor");
|
||||
|
||||
await page.goto(fixtureURL("anchor", attributes));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
const attributes = {
|
||||
href: "href",
|
||||
ping: "ping",
|
||||
|
@ -52,7 +35,22 @@ test.describe("Anchor", () => {
|
|||
for (const [attribute, value] of Object.entries(attributes)) {
|
||||
const attributeSpinalCase = spinalCase(attribute);
|
||||
|
||||
test(`should set the \`${attributeSpinalCase}\` attribute to \`${value}\` on the internal control`, async () => {
|
||||
test(`should set the \`${attributeSpinalCase}\` attribute to \`${value}\` on the internal control`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-anchor");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(root, [attribute, value]) => {
|
||||
const anchor = document.createElement("fast-anchor");
|
||||
anchor[attribute] = value;
|
||||
root.append(anchor);
|
||||
},
|
||||
[attribute, value]
|
||||
);
|
||||
|
||||
await expect(element).toHaveAttribute(attributeSpinalCase, `${value}`);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ export type AnchorOptions = StartEndOptions<FASTAnchor>;
|
|||
|
||||
/**
|
||||
* An Anchor Custom HTML Element.
|
||||
* Based largely on the {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | <a> element }.
|
||||
* Based largely on the {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | `<a>` element }.
|
||||
*
|
||||
* @slot start - Content which can be provided before the anchor content
|
||||
* @slot end - Content which can be provided after the anchor content
|
||||
|
@ -27,7 +27,7 @@ export class FASTAnchor extends FASTElement {
|
|||
* Prompts the user to save the linked URL. See {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a | <a> element } for more information.
|
||||
* @public
|
||||
* @remarks
|
||||
* HTML Attribute: download
|
||||
* HTML Attribute: `download`
|
||||
*/
|
||||
@attr
|
||||
public download: string;
|
||||
|
|
|
@ -39,8 +39,10 @@ const storyTemplate = html<StoryArgs<FASTAnchor>>`
|
|||
</fast-anchor>
|
||||
`;
|
||||
|
||||
export default {
|
||||
const meta: Meta<FASTAnchor> = {
|
||||
title: "Anchor",
|
||||
component: "fast-anchor",
|
||||
render: renderComponent(storyTemplate).bind({}),
|
||||
argTypes: {
|
||||
download: { control: "text" },
|
||||
href: { control: "text" },
|
||||
|
@ -72,30 +74,32 @@ export default {
|
|||
ariaRoledescription: { control: "text" },
|
||||
storyContent: { table: { disable: true } },
|
||||
},
|
||||
} as Meta<FASTAnchor>;
|
||||
};
|
||||
export default meta;
|
||||
|
||||
export const Anchor: Story<FASTAnchor> = renderComponent(storyTemplate).bind({});
|
||||
Anchor.args = {
|
||||
href: "https://www.fast.design/",
|
||||
storyContent: "Anchor",
|
||||
export const Anchor: Story<FASTAnchor> = {
|
||||
args: {
|
||||
href: "https://www.fast.design/",
|
||||
storyContent: "Anchor",
|
||||
},
|
||||
};
|
||||
|
||||
export const AnchorWithSlottedStartEnd: Story<FASTAnchor> = renderComponent(
|
||||
storyTemplate
|
||||
).bind({});
|
||||
AnchorWithSlottedStartEnd.args = {
|
||||
href: "https://www.fast.design/",
|
||||
storyContent: html`
|
||||
<svg slot="start" width="20" height="20"><use href="#test-icon" /></svg>
|
||||
Anchor
|
||||
<svg slot="end" width="20" height="20"><use href="#test-icon-2" /></svg>
|
||||
`,
|
||||
export const AnchorWithSlottedStartEnd: Story<FASTAnchor> = {
|
||||
args: {
|
||||
href: "https://www.fast.design/",
|
||||
storyContent: html`
|
||||
<svg slot="start" width="20" height="20"><use href="#test-icon" /></svg>
|
||||
Anchor
|
||||
<svg slot="end" width="20" height="20"><use href="#test-icon-2" /></svg>
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
||||
export const AnchorWithSlottedIconContent: Story<FASTAnchor> = Anchor.bind({});
|
||||
AnchorWithSlottedIconContent.args = {
|
||||
href: "https://www.fast.design/",
|
||||
storyContent: html`
|
||||
<svg width="20" height="20"><use href="#test-icon" /></svg>
|
||||
`,
|
||||
export const AnchorWithSlottedIconContent: Story = {
|
||||
args: {
|
||||
href: "https://www.fast.design/",
|
||||
storyContent: html`
|
||||
<svg width="20" height="20"><use href="#test-icon" /></svg>
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,29 +1,15 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTAnchoredRegion } from "./anchored-region.js";
|
||||
|
||||
test.describe("Anchored Region", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should set positioning modes to 'uncontrolled' by default", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-anchored-region");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-anchored-region");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("anchored-region--anchored-region"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set positioning modes to 'uncontrolled' by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-anchored-region></fast-anchored-region>
|
||||
`;
|
||||
|
@ -37,10 +23,13 @@ test.describe("Anchored Region", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should assign anchor and viewport elements by id", async () => {
|
||||
test("should assign anchor and viewport elements by id", async ({ page }) => {
|
||||
const element = page.locator("fast-anchored-region");
|
||||
const anchorId = "anchor";
|
||||
|
||||
await root.evaluate(
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { anchorId }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<div id="${anchorId}"></div>
|
||||
|
@ -61,8 +50,13 @@ test.describe("Anchored Region", () => {
|
|||
expect(anchorElementId).toBe(anchorId);
|
||||
});
|
||||
|
||||
test("should be sized to match content by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should be sized to match content by default", async ({ page }) => {
|
||||
const element = page.locator("fast-anchored-region");
|
||||
const content = element.locator("#content");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-anchored-region>
|
||||
<div id="content" style="width: 100px; height: 100px;"></div>
|
||||
|
@ -72,8 +66,6 @@ test.describe("Anchored Region", () => {
|
|||
|
||||
const elementClientHeight = await element.evaluate(node => node.clientHeight);
|
||||
|
||||
const content = element.locator("#content");
|
||||
|
||||
const contentClientHeight = await content.evaluate(node => node.clientHeight);
|
||||
|
||||
expect(elementClientHeight).toBe(contentClientHeight);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export {
|
||||
AnchoredRegionConfig,
|
||||
FlyoutPosBottom,
|
||||
FlyoutPosBottomFill,
|
||||
FlyoutPosTallest,
|
||||
|
@ -7,14 +6,14 @@ export {
|
|||
FlyoutPosTop,
|
||||
FlyoutPosTopFill,
|
||||
} from "./anchored-region-config.js";
|
||||
export type { AnchoredRegionConfig } from "./anchored-region-config.js";
|
||||
export { FASTAnchoredRegion } from "./anchored-region.js";
|
||||
export {
|
||||
AnchoredRegionPositionLabel,
|
||||
AutoUpdateMode,
|
||||
AxisPositioningMode,
|
||||
AxisScalingMode,
|
||||
Dimension,
|
||||
HorizontalPosition,
|
||||
VerticalPosition,
|
||||
} from "./anchored-region.options.js";
|
||||
export type { AxisPositioningMode, Dimension } from "./anchored-region.options.js";
|
||||
export { anchoredRegionTemplate } from "./anchored-region.template.js";
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
|
||||
const storyTemplate = html<StoryArgs<FASTAnchoredRegion>>`
|
||||
<div style="min-height: 100px">
|
||||
<fast-button class="anchor">Anchor</fast-button>
|
||||
<div class="anchor">Anchor</div>
|
||||
<fast-anchored-region
|
||||
class="region"
|
||||
?horizontal-inset="${x => x.horizontalInset}"
|
||||
|
@ -38,7 +38,7 @@ const storyTemplate = html<StoryArgs<FASTAnchoredRegion>>`
|
|||
</div>
|
||||
`;
|
||||
|
||||
export default {
|
||||
const meta: Meta<typeof FASTAnchoredRegion> = {
|
||||
title: "Anchored Region",
|
||||
args: {
|
||||
storyContent: html`
|
||||
|
@ -57,33 +57,33 @@ export default {
|
|||
anchorId: { table: { disable: true } },
|
||||
autoUpdateMode: {
|
||||
control: "select",
|
||||
options: Object.values(AutoUpdateMode),
|
||||
options: AutoUpdateMode,
|
||||
},
|
||||
fixedPlacement: { control: "boolean" },
|
||||
horizontalDefaultPosition: {
|
||||
control: "select",
|
||||
options: Object.values(HorizontalPosition),
|
||||
options: HorizontalPosition,
|
||||
},
|
||||
horizontalInset: { control: "boolean" },
|
||||
horizontalPositioningMode: {
|
||||
control: "select",
|
||||
options: Object.values(AxisPositioningMode),
|
||||
options: AxisPositioningMode,
|
||||
},
|
||||
horizontalScaling: {
|
||||
control: "select",
|
||||
options: Object.values(AxisScalingMode),
|
||||
options: AxisScalingMode,
|
||||
},
|
||||
horizontalThreshold: { control: "number" },
|
||||
horizontalViewportLock: { control: "boolean" },
|
||||
storyContent: { table: { disable: true } },
|
||||
verticalDefaultPosition: {
|
||||
control: "select",
|
||||
options: Object.values(VerticalPosition),
|
||||
options: VerticalPosition,
|
||||
},
|
||||
verticalInset: { control: "boolean" },
|
||||
verticalPositioningMode: {
|
||||
control: "select",
|
||||
options: Object.values(AxisPositioningMode),
|
||||
options: AxisPositioningMode,
|
||||
},
|
||||
verticalScaling: {
|
||||
control: "select",
|
||||
|
@ -93,22 +93,25 @@ export default {
|
|||
verticalViewportLock: { control: "boolean" },
|
||||
viewport: { control: "text" },
|
||||
},
|
||||
decorators: [
|
||||
(Story, { args }) => {
|
||||
// IDs are generated to ensure that they're unique for the docs page
|
||||
const renderedStory = Story() as DocumentFragment;
|
||||
const anchor = renderedStory.querySelector(".anchor") as HTMLElement;
|
||||
const region = renderedStory.querySelector(".region") as HTMLElement;
|
||||
};
|
||||
|
||||
const anchorId = args.anchorId ?? uniqueId("anchor");
|
||||
meta.decorators = [
|
||||
(Story, { args }) => {
|
||||
// IDs are generated to ensure that they're unique for the docs page
|
||||
const renderedStory = Story() as DocumentFragment;
|
||||
const anchor = renderedStory.querySelector(".anchor") as FASTAnchoredRegion;
|
||||
const region = renderedStory.querySelector(".region") as HTMLElement;
|
||||
|
||||
anchor.id = anchorId;
|
||||
region.id = uniqueId("region");
|
||||
region.setAttribute("anchor", anchorId);
|
||||
return renderedStory;
|
||||
},
|
||||
],
|
||||
} as Meta<FASTAnchoredRegion>;
|
||||
const anchorId = args.anchorId ?? uniqueId("anchor");
|
||||
|
||||
anchor.id = anchorId;
|
||||
region.id = uniqueId("region");
|
||||
region.setAttribute("anchor", anchorId);
|
||||
return renderedStory;
|
||||
},
|
||||
];
|
||||
|
||||
export default meta;
|
||||
|
||||
export const AnchoredRegion: Story<FASTAnchoredRegion> = renderComponent(
|
||||
storyTemplate
|
||||
|
|
|
@ -1,33 +1,14 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTBreadcrumbItem } from "./breadcrumb-item.js";
|
||||
|
||||
test.describe("Breadcrumb item", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
test("should include a `role` of `listitem`", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-breadcrumb-item");
|
||||
|
||||
element = page.locator("fast-breadcrumb-item");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(".control");
|
||||
|
||||
await page.goto(fixtureURL("breadcrumb-item--breadcrumb-item"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a `role` of `listitem`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb-item></fast-breadcrumb-item>
|
||||
`;
|
||||
|
@ -36,8 +17,14 @@ test.describe("Breadcrumb item", () => {
|
|||
await expect(element.locator("> div")).toHaveAttribute("role", "listitem");
|
||||
});
|
||||
|
||||
test("should render an internal anchor when the `href` attribute is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an internal anchor when the `href` attribute is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-breadcrumb-item");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb-item></fast-breadcrumb-item>
|
||||
`;
|
||||
|
@ -54,8 +41,14 @@ test.describe("Breadcrumb item", () => {
|
|||
await expect(element.locator("a")).toHaveCount(1);
|
||||
});
|
||||
|
||||
test("should render an internal anchor when the `href` attribute is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an internal anchor when the `href` attribute is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-breadcrumb-item");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb-item href="https://fast.design"></fast-breadcrumb-item>
|
||||
`;
|
||||
|
@ -72,8 +65,14 @@ test.describe("Breadcrumb item", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should add an element with a class of `separator` when the `separator` property is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add an element with a class of `separator` when the `separator` property is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-breadcrumb-item");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb-item></fast-breadcrumb-item>
|
||||
`;
|
||||
|
@ -117,19 +116,27 @@ test.describe("Breadcrumb item", () => {
|
|||
};
|
||||
|
||||
for (const [attribute, value] of Object.entries(attributes)) {
|
||||
const attrToken = spinalCase(attribute);
|
||||
const attributeSpinalCase = spinalCase(attribute);
|
||||
|
||||
test(`should set the \`${attrToken}\` attribute to \`${value}\` on the internal anchor`, async () => {
|
||||
await root.evaluate(
|
||||
(node, { attrToken, value }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb-item ${attrToken}="${value}" href="#"></fast-breadcrumb-item>
|
||||
`;
|
||||
test(`should set the \`${attributeSpinalCase}\` attribute to \`${value}\` on the internal anchor`, async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-breadcrumb-item");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(root, [attribute, value]) => {
|
||||
const breadcrumbItem = document.createElement("fast-breadcrumb-item");
|
||||
breadcrumbItem[attribute] = value;
|
||||
root.append(breadcrumbItem);
|
||||
},
|
||||
{ attrToken, value }
|
||||
[attribute, value]
|
||||
);
|
||||
|
||||
await expect(control).toHaveAttribute(attrToken, `${value}`);
|
||||
await expect(control).toHaveAttribute(attributeSpinalCase, `${value}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTBreadcrumb } from "./breadcrumb.js";
|
||||
|
||||
test.describe("Breadcrumb", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should have a role of 'navigation'", async ({ page }) => {
|
||||
const element = page.locator("fast-breadcrumb");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-breadcrumb");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("breadcrumb--breadcrumb"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of 'navigation'", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb></fast-breadcrumb>
|
||||
`;
|
||||
|
@ -32,8 +16,14 @@ test.describe("Breadcrumb", () => {
|
|||
await expect(element).toHaveAttribute("role", "navigation");
|
||||
});
|
||||
|
||||
test("should include an internal element with a `role` of `list`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should include an internal element with a `role` of `list`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-breadcrumb");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb></fast-breadcrumb>
|
||||
`;
|
||||
|
@ -42,8 +32,13 @@ test.describe("Breadcrumb", () => {
|
|||
await expect(element.locator(".list")).toHaveAttribute("role", "list");
|
||||
});
|
||||
|
||||
test("should not render a separator on last item", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not render a separator on last item", async ({ page }) => {
|
||||
const element = page.locator("fast-breadcrumb");
|
||||
const items = element.locator("fast-breadcrumb-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb>
|
||||
<fast-breadcrumb-item>Item 1</fast-breadcrumb-item>
|
||||
|
@ -53,15 +48,19 @@ test.describe("Breadcrumb", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
const items = element.locator("fast-breadcrumb-item");
|
||||
|
||||
await expect(items).toHaveCount(3);
|
||||
|
||||
await expect(items.last()).toHaveJSProperty("separator", false);
|
||||
});
|
||||
|
||||
test("should set `aria-current` on the internal anchor of the last node when `href` is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `aria-current` on the internal anchor of the last node when `href` is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-breadcrumb");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb>
|
||||
<fast-breadcrumb-item>Item 1</fast-breadcrumb-item>
|
||||
|
@ -76,8 +75,14 @@ test.describe("Breadcrumb", () => {
|
|||
).toHaveAttribute("aria-current", "page");
|
||||
});
|
||||
|
||||
test("should remove `aria-current` from any prior breadcrumb item children with child anchors when a new node is appended", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should remove `aria-current` from any prior breadcrumb item children with child anchors when a new node is appended", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-breadcrumb");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-breadcrumb>
|
||||
<fast-breadcrumb-item>Item 1</fast-breadcrumb-item>
|
||||
|
|
|
@ -1,33 +1,18 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTButton } from "./button.js";
|
||||
|
||||
test.describe("Button", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
test("should set the `disabled` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
element = page.locator("fast-button");
|
||||
const control = element.locator(".control");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(".control");
|
||||
|
||||
await page.goto(fixtureURL("button--button"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set the `disabled` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-button disabled></fast-button>
|
||||
`;
|
||||
|
@ -42,8 +27,16 @@ test.describe("Button", () => {
|
|||
await expect(control).not.toHaveBooleanAttribute("disabled");
|
||||
});
|
||||
|
||||
test("should set the `formnovalidate` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `formnovalidate` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-button formnovalidate></fast-button>
|
||||
`;
|
||||
|
@ -94,8 +87,16 @@ test.describe("Button", () => {
|
|||
for (const [attribute, value] of Object.entries(attributes)) {
|
||||
const attrToken = spinalCase(attribute);
|
||||
|
||||
test(`should set the \`${attrToken}\` attribute to \`${value}\``, async () => {
|
||||
await root.evaluate(
|
||||
test(`should set the \`${attrToken}\` attribute to \`${value}\``, async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { attrToken, value }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-button ${attrToken}="${value}"></fast-button>
|
||||
|
@ -109,8 +110,16 @@ test.describe("Button", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set the `form` attribute on the internal button when `formId` is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `form` attribute on the internal button when `formId` is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-button></fast-button>
|
||||
`;
|
||||
|
@ -123,8 +132,16 @@ test.describe("Button", () => {
|
|||
await expect(control).toHaveAttribute("form", "foo");
|
||||
});
|
||||
|
||||
test("should set the `autofocus` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `autofocus` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-button autofocus></fast-button>
|
||||
`;
|
||||
|
@ -139,8 +156,14 @@ test.describe("Button", () => {
|
|||
await expect(control).not.toHaveBooleanAttribute("autofocus");
|
||||
});
|
||||
|
||||
test("of type `submit` should submit the parent form when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("of type `submit` should submit the parent form when clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-button type="submit">Submit Button</fast-button>
|
||||
|
@ -167,8 +190,14 @@ test.describe("Button", () => {
|
|||
expect(wasSubmitted).toBeTruthy();
|
||||
});
|
||||
|
||||
test("of type `reset` should reset the parent form when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("of type `reset` should reset the parent form when clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<input type="text" value="foo" />
|
||||
|
@ -194,8 +223,12 @@ test.describe("Button", () => {
|
|||
expect(wasReset).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should not propagate when clicked and `disabled` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not propagate when clicked and `disabled` is true", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-button");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-button disabled>Disabled Button</fast-button>
|
||||
`;
|
||||
|
|
|
@ -1,30 +1,10 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTCalendar } from "./calendar.js";
|
||||
import { DateFormatter } from "./date-formatter.js";
|
||||
|
||||
test.describe("Calendar", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
|
||||
element = page.locator("fast-calendar");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("calendar--calendar"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test.describe("DateFormatter", () => {
|
||||
test("should be able to set properties on construction", async () => {
|
||||
test("should be able to set properties on construction", () => {
|
||||
const locale = "en-US";
|
||||
const dayFormat = "2-digit";
|
||||
const monthFormat = "narrow";
|
||||
|
@ -50,14 +30,14 @@ test.describe("Calendar", () => {
|
|||
expect(formatter.date.getFullYear()).toBe(2021);
|
||||
});
|
||||
|
||||
test("should return a date string for today by default", async () => {
|
||||
test("should return a date string for today by default", () => {
|
||||
const formatter = new DateFormatter();
|
||||
const today = new Date();
|
||||
|
||||
expect(formatter.getDate()).toBe(formatter.getDate(today));
|
||||
});
|
||||
|
||||
test("should be able to get a date string for a specific date", async () => {
|
||||
test("should be able to get a date string for a specific date", () => {
|
||||
const formatter = new DateFormatter();
|
||||
const day = 2;
|
||||
const month = 1;
|
||||
|
@ -74,13 +54,13 @@ test.describe("Calendar", () => {
|
|||
).toBe(dateString);
|
||||
});
|
||||
|
||||
test("should default formatting to [weekday='long'], [month='long'] [day='numeric'], [year='numeric'] string", async () => {
|
||||
test("should default formatting to [weekday='long'], [month='long'] [day='numeric'], [year='numeric'] string", () => {
|
||||
const formatter = new DateFormatter({ date: "1-1-2020" });
|
||||
|
||||
expect(formatter.getDate()).toBe("Wednesday, January 1, 2020");
|
||||
});
|
||||
|
||||
test("should be able to change formats", async () => {
|
||||
test("should be able to change formats", () => {
|
||||
const formatter = new DateFormatter({
|
||||
weekdayFormat: undefined,
|
||||
monthFormat: "short",
|
||||
|
@ -101,21 +81,21 @@ test.describe("Calendar", () => {
|
|||
).toBe("J 01, 20");
|
||||
});
|
||||
|
||||
test("should return todays day by default for getDay()", async () => {
|
||||
test("should return todays day by default for getDay()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
const today = new Date();
|
||||
|
||||
expect(formatter.getDay()).toBe(today.getDate().toString());
|
||||
});
|
||||
|
||||
test("should return formatted days with getDay()", async () => {
|
||||
test("should return formatted days with getDay()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
|
||||
expect(formatter.getDay(14)).toBe("14");
|
||||
expect(formatter.getDay(8, "2-digit")).toBe("08");
|
||||
});
|
||||
|
||||
test("should return this month by default for getMonth()", async () => {
|
||||
test("should return this month by default for getMonth()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
const today = new Date();
|
||||
const months = [
|
||||
|
@ -136,7 +116,7 @@ test.describe("Calendar", () => {
|
|||
expect(formatter.getMonth()).toBe(months[today.getMonth()]);
|
||||
});
|
||||
|
||||
test("should return formatted month with getMonth()", async () => {
|
||||
test("should return formatted month with getMonth()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
|
||||
expect(formatter.getMonth(1)).toBe("January");
|
||||
|
@ -146,21 +126,21 @@ test.describe("Calendar", () => {
|
|||
expect(formatter.getMonth(5, "2-digit")).toBe("05");
|
||||
});
|
||||
|
||||
test("should return this year by default for getYear()", async () => {
|
||||
test("should return this year by default for getYear()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
const today = new Date();
|
||||
|
||||
expect(formatter.getYear()).toBe(today.getFullYear().toString());
|
||||
});
|
||||
|
||||
test("should return formatted year with getYear()", async () => {
|
||||
test("should return formatted year with getYear()", () => {
|
||||
const formatter = new DateFormatter({ yearFormat: "2-digit" });
|
||||
|
||||
expect(formatter.getYear(2012)).toBe("12");
|
||||
expect(formatter.getYear(2015, "numeric")).toBe("2015");
|
||||
});
|
||||
|
||||
test("should return formatted weekday string with getWeekday()", async () => {
|
||||
test("should return formatted weekday string with getWeekday()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
|
||||
//defaults to sunday
|
||||
|
@ -170,7 +150,7 @@ test.describe("Calendar", () => {
|
|||
expect(formatter.getWeekday(4, "narrow")).toBe("T");
|
||||
});
|
||||
|
||||
test("should return a list of formatted weekday labels with getWeekdays()", async () => {
|
||||
test("should return a list of formatted weekday labels with getWeekdays()", () => {
|
||||
const formatter = new DateFormatter();
|
||||
const weekdays = [
|
||||
"Sunday",
|
||||
|
@ -193,7 +173,7 @@ test.describe("Calendar", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should return a localized string when setting the locale", async () => {
|
||||
test("should return a localized string when setting the locale", () => {
|
||||
const formatter = new DateFormatter({ locale: "fr-FR", date: "3-1-2015" });
|
||||
|
||||
expect(formatter.getDate()).toBe("dimanche 1 mars 2015");
|
||||
|
@ -207,8 +187,12 @@ test.describe("Calendar", () => {
|
|||
});
|
||||
|
||||
test.describe("Defaults", () => {
|
||||
test("should default to the current month and year", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should default to the current month and year", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar></fast-calendar>
|
||||
`;
|
||||
|
@ -220,8 +204,12 @@ test.describe("Calendar", () => {
|
|||
await expect(element).toHaveJSProperty("year", today.getFullYear());
|
||||
});
|
||||
|
||||
test("should return 5 weeks of days for August 2021", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return 5 weeks of days for August 2021", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="8" year="2021"></fast-calendar>
|
||||
`;
|
||||
|
@ -240,8 +228,14 @@ test.describe("Calendar", () => {
|
|||
await expect(day).toHaveCount(35);
|
||||
});
|
||||
|
||||
test("should return 6 weeks of days for August 2021 when min-weeks is set to 6", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return 6 weeks of days for August 2021 when min-weeks is set to 6", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="8" year="2021" min-weeks="6"></fast-calendar>
|
||||
`;
|
||||
|
@ -260,8 +254,12 @@ test.describe("Calendar", () => {
|
|||
await expect(day).toHaveCount(42);
|
||||
});
|
||||
|
||||
test("should highlight the current date", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should highlight the current date", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar></fast-calendar>
|
||||
`;
|
||||
|
@ -276,8 +274,14 @@ test.describe("Calendar", () => {
|
|||
});
|
||||
|
||||
test.describe("Month info", () => {
|
||||
test("should display 31 days for the month of January in the year 2022", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should display 31 days for the month of January in the year 2022", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2022" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -292,8 +296,14 @@ test.describe("Calendar", () => {
|
|||
await expect(days).toHaveCount(31);
|
||||
});
|
||||
|
||||
test("should display 28 days for the month of February in the year 2022", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should display 28 days for the month of February in the year 2022", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="2" year="2022" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -308,8 +318,14 @@ test.describe("Calendar", () => {
|
|||
await expect(days).toHaveCount(28);
|
||||
});
|
||||
|
||||
test("should display 29 days for the month of February in the year 2020", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should display 29 days for the month of February in the year 2020", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="2" year="2020" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -324,8 +340,12 @@ test.describe("Calendar", () => {
|
|||
await expect(days).toHaveCount(29);
|
||||
});
|
||||
|
||||
test("should start on Friday for January 2021", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should start on Friday for January 2021", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -340,8 +360,12 @@ test.describe("Calendar", () => {
|
|||
await expect(days.nth(5)).toHaveText("1");
|
||||
});
|
||||
|
||||
test("should start on Monday for February 2021", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should start on Monday for February 2021", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="2" year="2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -357,9 +381,13 @@ test.describe("Calendar", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test.describe("Labels", async () => {
|
||||
test("should return January for month 1", async () => {
|
||||
await root.evaluate(node => {
|
||||
test.describe("Labels", () => {
|
||||
test("should return January for month 1", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -372,8 +400,12 @@ test.describe("Calendar", () => {
|
|||
).toBe("January");
|
||||
});
|
||||
|
||||
test("should return Jan for month 1 and short format", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return Jan for month 1 and short format", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" month-format="short" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -386,8 +418,12 @@ test.describe("Calendar", () => {
|
|||
).toBe("Jan");
|
||||
});
|
||||
|
||||
test("should return Mon for Monday by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return Mon for Monday by default", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -400,8 +436,12 @@ test.describe("Calendar", () => {
|
|||
).toBe("Mon");
|
||||
});
|
||||
|
||||
test("should return Monday weekday for long format", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return Monday weekday for long format", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" weekday-format="long" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -414,8 +454,12 @@ test.describe("Calendar", () => {
|
|||
).toBe("Monday");
|
||||
});
|
||||
|
||||
test("should return M for Monday for narrow format", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return M for Monday for narrow format", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" weekday-format="narrow" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -429,9 +473,13 @@ test.describe("Calendar", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test.describe("Localization", async () => {
|
||||
test(`should be "mai" for the month May in French`, async () => {
|
||||
await root.evaluate(node => {
|
||||
test.describe("Localization", () => {
|
||||
test(`should be "mai" for the month May in French`, async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="5" year="2021" locale="fr" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -444,8 +492,14 @@ test.describe("Calendar", () => {
|
|||
).toBe("mai");
|
||||
});
|
||||
|
||||
test("should have French weekday labels for the fr-FR market", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have French weekday labels for the fr-FR market", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" locale="fr-FR" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -466,8 +520,14 @@ test.describe("Calendar", () => {
|
|||
await expect(weekdayLabels).toHaveText(frenchWeekdays);
|
||||
});
|
||||
|
||||
test('should set the formatted `year` property to "1942" when the `year` attribute is "2021" for the Hindu calendar', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the formatted `year` property to "1942" when the `year` attribute is "2021" for the Hindu calendar', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="6" year="2021" locale="hi-IN-u-ca-indian"></fast-calendar>
|
||||
`;
|
||||
|
@ -480,8 +540,14 @@ test.describe("Calendar", () => {
|
|||
).toBe("1942 शक");
|
||||
});
|
||||
|
||||
test('should set the formatted `year` property to "2564" when the `year` attribute is "2021" for the Buddhist calendar', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the formatted `year` property to "2564" when the `year` attribute is "2021" for the Buddhist calendar', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="6" year="2021" locale="th-TH-u-ca-buddhist"></fast-calendar>
|
||||
`;
|
||||
|
@ -494,8 +560,14 @@ test.describe("Calendar", () => {
|
|||
).toBe("พ.ศ. 2564");
|
||||
});
|
||||
|
||||
test("should not be RTL for languages that are not Arabic or Hebrew", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not be RTL for languages that are not Arabic or Hebrew", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="1" year="2021" locale="fr-FR" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -514,9 +586,12 @@ test.describe("Calendar", () => {
|
|||
}
|
||||
});
|
||||
|
||||
/* FIXME this test is an incorrect assertion */
|
||||
test.skip("Should be RTL for Arabic language", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("Should be RTL for Arabic language", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="8" year="2021" locale="ar-XE-u-ca-islamic-nu-arab" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -528,13 +603,19 @@ test.describe("Calendar", () => {
|
|||
nodes.map(node => node.innerHTML.trim())
|
||||
);
|
||||
|
||||
expect(parseInt(dateStrings[0]) < parseInt(dateStrings[1])).toBeFalsy();
|
||||
expect(
|
||||
parseInt(dateStrings[0], 10) < parseInt(dateStrings[1], 10)
|
||||
).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Day states", async () => {
|
||||
test("should not show date as disabled by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test.describe("Day states", () => {
|
||||
test("should not show date as disabled by default", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="5" year="2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -559,8 +640,14 @@ test.describe("Calendar", () => {
|
|||
await expect(disabled).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should show date as disabled when added to disabled-dates attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should show date as disabled when added to disabled-dates attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="5" year="2021" disabled-dates="5-6-2021,5-7-2021,5-8-2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -588,8 +675,12 @@ test.describe("Calendar", () => {
|
|||
await expect(disabled).toHaveCount(3);
|
||||
});
|
||||
|
||||
test("should not show date as selected by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not show date as selected by default", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="5" year="2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -602,21 +693,26 @@ test.describe("Calendar", () => {
|
|||
).toBe(false);
|
||||
|
||||
expect(
|
||||
element.evaluate(
|
||||
(node: FASTCalendar) =>
|
||||
node
|
||||
.getDayClassNames({ month: 5, day: 7, year: 2021 })
|
||||
.indexOf("selected") === -1
|
||||
await element.evaluate((node: FASTCalendar) =>
|
||||
node
|
||||
.getDayClassNames({ month: 5, day: 7, year: 2021 })
|
||||
.indexOf("selected")
|
||||
)
|
||||
).toBeTruthy();
|
||||
).toBe(-1);
|
||||
|
||||
const selected = element.locator(".selected");
|
||||
|
||||
await expect(selected).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should show date as selected when added to selected-dates attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should show date as selected when added to selected-dates attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-calendar");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-calendar month="5" year="2021" selected-dates="5-6-2021,5-7-2021,5-8-2021" readonly></fast-calendar>
|
||||
`;
|
||||
|
@ -629,18 +725,17 @@ test.describe("Calendar", () => {
|
|||
).toBe(true);
|
||||
|
||||
expect(
|
||||
await element.evaluate(
|
||||
(node: FASTCalendar) =>
|
||||
node
|
||||
.getDayClassNames({
|
||||
month: 5,
|
||||
day: 7,
|
||||
year: 2021,
|
||||
selected: true,
|
||||
})
|
||||
.indexOf("selected") >= 0
|
||||
await element.evaluate((node: FASTCalendar) =>
|
||||
node
|
||||
.getDayClassNames({
|
||||
month: 5,
|
||||
day: 7,
|
||||
year: 2021,
|
||||
selected: true,
|
||||
})
|
||||
.indexOf("selected")
|
||||
)
|
||||
).toBeTruthy();
|
||||
).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const selected = element.locator(".selected");
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { attr, FASTElement, nullableNumberConverter } from "@microsoft/fast-element";
|
||||
import { keyEnter } from "@microsoft/fast-web-utilities";
|
||||
import type { StartEndOptions } from "../patterns/start-end.js";
|
||||
import { StartEnd } from "../patterns/start-end.js";
|
||||
import type { TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
import { applyMixins } from "../utilities/apply-mixins.js";
|
||||
import type { StaticallyComposableHTML } from "../utilities/template-helpers.js";
|
||||
import { StartEnd, TemplateElementDependency } from "../patterns/index.js";
|
||||
import type { StartEndOptions } from "../patterns/start-end.js";
|
||||
import { DayFormat, MonthFormat, WeekdayFormat, YearFormat } from "./calendar.options.js";
|
||||
import { DateFormatter } from "./date-formatter.js";
|
||||
|
||||
|
|
|
@ -1,32 +1,13 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTCheckbox } from "./checkbox.js";
|
||||
|
||||
test.describe("Checkbox", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let form: Locator;
|
||||
test("should have a role of `checkbox`", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
element = page.locator("fast-checkbox");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
form = page.locator("form");
|
||||
|
||||
await page.goto(fixtureURL("checkbox--checkbox"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `checkbox`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -34,8 +15,12 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("role", "checkbox");
|
||||
});
|
||||
|
||||
test("should set a tabindex of 0 on the element", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a tabindex of 0 on the element", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -46,8 +31,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should set a default `aria-checked` value when `checked` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `aria-checked` value when `checked` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -58,8 +49,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-checked` attribute equal to the `checked` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-checked` attribute equal to the `checked` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox checked></fast-checkbox>
|
||||
`;
|
||||
|
@ -74,8 +71,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should NOT set a default `aria-required` value when `required` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a default `aria-required` value when `required` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -86,8 +89,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-required", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-required` attribute equal to the `required` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-required` attribute equal to the `required` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -106,8 +115,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-required", "false");
|
||||
});
|
||||
|
||||
test("should set a default `aria-disabled` value when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `aria-disabled` value when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -118,8 +133,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -138,8 +159,12 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should NOT set a tabindex when `disabled` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a tabindex when `disabled` is true", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox disabled></fast-checkbox>
|
||||
`;
|
||||
|
@ -150,8 +175,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).not.toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should set the aria-checked value to 'mixed' when indeterminate property is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the aria-checked value to 'mixed' when indeterminate property is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -170,8 +201,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should set off `indeterminate` on `checked` change by user click", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set off `indeterminate` on `checked` change by user click", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox>checkbox</fast-checkbox>
|
||||
`;
|
||||
|
@ -188,8 +225,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveJSProperty("indeterminate", false);
|
||||
});
|
||||
|
||||
test("should set off `indeterminate` on `checked` change by user keypress", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set off `indeterminate` on `checked` change by user keypress", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -206,8 +249,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveJSProperty("indeterminate", false);
|
||||
});
|
||||
|
||||
test("should add a class of `label` to the internal label when default slotted content exists", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add a class of `label` to the internal label when default slotted content exists", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox>
|
||||
<span>Label</span>
|
||||
|
@ -220,8 +269,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(label).toHaveClass(/label/);
|
||||
});
|
||||
|
||||
test("should add classes of `label` and `label__hidden` to the internal label when default slotted content exists", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add classes of `label` and `label__hidden` to the internal label when default slotted content exists", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox>
|
||||
<span>Label</span>
|
||||
|
@ -240,8 +295,14 @@ test.describe("Checkbox", () => {
|
|||
await expect(label).toHaveClass(/label label__hidden/);
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -255,29 +316,37 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveJSProperty("value", initialValue);
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` attribute when set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` attribute when set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox value="foo"></fast-checkbox>
|
||||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
const value = await element.evaluate((node: FASTCheckbox) => node.value);
|
||||
|
||||
expect(value).toBe("foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` attribute when set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` attribute when set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
const expectedValue = "foobar";
|
||||
|
||||
await element.evaluate((node: FASTCheckbox, expectedValue) => {
|
||||
|
@ -287,8 +356,12 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveJSProperty("value", expectedValue);
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` property when set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` property when set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-checkbox></fast-checkbox>
|
||||
`;
|
||||
|
@ -307,8 +380,12 @@ test.describe("Checkbox", () => {
|
|||
expect(value).toBe(expectedValue);
|
||||
});
|
||||
|
||||
test("should be invalid when unchecked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should be invalid when unchecked", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-checkbox required></fast-checkbox>
|
||||
|
@ -321,8 +398,12 @@ test.describe("Checkbox", () => {
|
|||
).toBe(true);
|
||||
});
|
||||
|
||||
test("should be valid when checked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should be valid when checked", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-checkbox required>checkbox</fast-checkbox>
|
||||
|
@ -339,8 +420,16 @@ test.describe("Checkbox", () => {
|
|||
).toBe(false);
|
||||
});
|
||||
|
||||
test("should set the `checked` property to false if the `checked` attribute is unset", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `checked` property to false if the `checked` attribute is unset", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
const form = page.locator("form");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-checkbox></fast-checkbox>
|
||||
|
@ -363,8 +452,16 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveJSProperty("checked", false);
|
||||
});
|
||||
|
||||
test("should set its checked property to true if the checked attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its checked property to true if the checked attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
const form = page.locator("form");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-checkbox></fast-checkbox>
|
||||
|
@ -387,8 +484,16 @@ test.describe("Checkbox", () => {
|
|||
await expect(element).toHaveJSProperty("checked", true);
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where checked attribute modifications change the checked property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where checked attribute modifications change the checked property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-checkbox");
|
||||
|
||||
const form = page.locator("form");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-checkbox required></fast-checkbox>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { html } from "@microsoft/fast-element";
|
||||
import { css } from "@microsoft/fast-element";
|
||||
import { css, html } from "@microsoft/fast-element";
|
||||
import checkedIndicator from "../../../statics/svg/checked-indicator.svg";
|
||||
import { FASTCheckbox } from "../checkbox.js";
|
||||
import { checkboxTemplate } from "../checkbox.template.js";
|
||||
|
||||
|
@ -133,21 +133,10 @@ const styles = css`
|
|||
FASTCheckbox.define({
|
||||
name: "fast-checkbox",
|
||||
template: checkboxTemplate({
|
||||
checkedIndicator: /* html */ html`
|
||||
<svg
|
||||
part="checked-indicator"
|
||||
class="checked-indicator"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.143 12.6697L15.235 4.5L16.8 5.90363L8.23812 15.7667L3.80005 11.2556L5.27591 9.7555L8.143 12.6697Z"
|
||||
/>
|
||||
</svg>
|
||||
checkedIndicator: html`
|
||||
<div part="checked-indicator">${html.partial(checkedIndicator)}</div>
|
||||
`,
|
||||
indeterminateIndicator: /* html */ html`
|
||||
indeterminateIndicator: html`
|
||||
<div part="indeterminate-indicator" class="indeterminate-indicator"></div>
|
||||
`,
|
||||
}),
|
||||
|
|
|
@ -1,32 +1,17 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTCombobox } from "./combobox.js";
|
||||
|
||||
test.describe("Combobox", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
test('should include a control with a `role` attribute equal to "combobox"', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
element = page.locator("fast-combobox");
|
||||
const control = element.locator(`input[role="combobox"]`);
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(`input[role="combobox"]`);
|
||||
|
||||
await page.goto(fixtureURL("combobox--combobox"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test('should include a control with a `role` attribute equal to "combobox"', async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -39,8 +24,14 @@ test.describe("Combobox", () => {
|
|||
await expect(control).toHaveCount(1);
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -65,8 +56,14 @@ test.describe("Combobox", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set and remove the `tabindex` attribute based on the value of the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set and remove the `tabindex` attribute based on the value of the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox disabled>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -85,8 +82,16 @@ test.describe("Combobox", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should NOT set the `value` property to the first available option", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set the `value` property to the first available option", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
const control = element.locator(`input[role="combobox"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -101,8 +106,16 @@ test.describe("Combobox", () => {
|
|||
await expect(control).toHaveValue("");
|
||||
});
|
||||
|
||||
test("should set the `placeholder` attribute on the internal control equal to the `placeholder` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `placeholder` attribute on the internal control equal to the `placeholder` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
const control = element.locator(`input[role="combobox"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox placeholder="placeholder text">
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -117,8 +130,16 @@ test.describe("Combobox", () => {
|
|||
await expect(control).toHaveAttribute("placeholder", "placeholder text");
|
||||
});
|
||||
|
||||
test("should set the control's `aria-controls` attribute to the ID of the internal listbox element while open", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the control's `aria-controls` attribute to the ID of the internal listbox element while open", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
const control = element.locator(`input[role="combobox"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -147,8 +168,16 @@ test.describe("Combobox", () => {
|
|||
await expect(control).toHaveAttribute("aria-controls", "");
|
||||
});
|
||||
|
||||
test("should set the control's `aria-activedescendant` property to the ID of the currently selected option while open", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the control's `aria-activedescendant` property to the ID of the currently selected option while open", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
const control = element.locator(`input[role="combobox"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -166,7 +195,7 @@ test.describe("Combobox", () => {
|
|||
node.open = true;
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute("aria-activedescendant", "");
|
||||
await expect(element).not.toHaveAttribute("aria-activedescendant");
|
||||
|
||||
const optionsCount = await options.count();
|
||||
|
||||
|
@ -188,11 +217,17 @@ test.describe("Combobox", () => {
|
|||
|
||||
await expect(control).hasAttribute("aria-activedescendant");
|
||||
|
||||
await expect(element).toHaveAttribute("aria-activedescendant", "");
|
||||
await expect(element).not.toHaveAttribute("aria-activedescendant");
|
||||
});
|
||||
|
||||
test("should set its value to the first option with the `selected` attribute present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its value to the first option with the `selected` attribute present", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const combobox = document.createElement("fast-combobox");
|
||||
|
@ -216,8 +251,14 @@ test.describe("Combobox", () => {
|
|||
await expect(element).toHaveJSProperty("value", "two");
|
||||
});
|
||||
|
||||
test("should return the same value when the `value` property is set before connecting", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the same value when the `value` property is set before connecting", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const combobox = document.createElement("fast-combobox") as FASTCombobox;
|
||||
|
@ -228,8 +269,14 @@ test.describe("Combobox", () => {
|
|||
expect(await element.evaluate((node: FASTCombobox) => node.value)).toBe("test");
|
||||
});
|
||||
|
||||
test("should return the same value when the `value` property is set after connecting", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the same value when the `value` property is set after connecting", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const combobox = document.createElement("fast-combobox") as FASTCombobox;
|
||||
|
@ -243,8 +290,14 @@ test.describe("Combobox", () => {
|
|||
await expect(element).toHaveJSProperty("value", "test");
|
||||
});
|
||||
|
||||
test("should display the listbox when the `open` property is true before connecting", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should display the listbox when the `open` property is true before connecting", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -267,121 +320,137 @@ test.describe("Combobox", () => {
|
|||
await expect(listbox).toBeVisible();
|
||||
});
|
||||
|
||||
test.describe(
|
||||
"should NOT emit a 'change' event when the value changes by user input while open",
|
||||
() => {
|
||||
test("via arrow down key", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
test.describe("should NOT emit a 'change' event when the value changes by user input while open", () => {
|
||||
test("via arrow down key", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-combobox>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.click();
|
||||
|
||||
await element.locator(".listbox").waitFor({ state: "visible" });
|
||||
|
||||
await expect(element).toHaveBooleanAttribute("open");
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
Promise.race<boolean>([
|
||||
new Promise(resolve => {
|
||||
node.addEventListener("change", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve => setTimeout(() => resolve(false), 100)),
|
||||
])
|
||||
),
|
||||
element.press("ArrowDown"),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBeFalsy();
|
||||
});
|
||||
|
||||
test("via arrow up key", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
await element.click();
|
||||
|
||||
await element.locator(".listbox").waitFor({ state: "visible" });
|
||||
|
||||
await expect(element).toHaveBooleanAttribute("open");
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
Promise.race<boolean>([
|
||||
new Promise(resolve => {
|
||||
node.addEventListener("change", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve =>
|
||||
requestAnimationFrame(() => setTimeout(() => resolve(false)))
|
||||
),
|
||||
])
|
||||
),
|
||||
element.press("ArrowDown"),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBeFalsy();
|
||||
});
|
||||
|
||||
test("via arrow up key", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-combobox>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTCombobox) => {
|
||||
node.value = "two";
|
||||
});
|
||||
|
||||
await element.click();
|
||||
|
||||
await element.locator(".listbox").waitFor({ state: "visible" });
|
||||
|
||||
expect(
|
||||
await element.evaluate(node => node.hasAttribute("open"))
|
||||
).toBeTruthy();
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
Promise.race<boolean>([
|
||||
new Promise(resolve => {
|
||||
node.addEventListener("change", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve => setTimeout(() => resolve(false), 100)),
|
||||
])
|
||||
),
|
||||
element.press("ArrowUp"),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBeFalsy();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
test.describe(
|
||||
"should NOT emit a 'change' event when the value changes by programmatic interaction",
|
||||
() => {
|
||||
test("via end key", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
await element.evaluate((node: FASTCombobox) => {
|
||||
node.value = "two";
|
||||
});
|
||||
|
||||
await element.click();
|
||||
|
||||
await element.locator(".listbox").waitFor({ state: "visible" });
|
||||
|
||||
expect(
|
||||
await element.evaluate(node => node.hasAttribute("open"))
|
||||
).toBeTruthy();
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
Promise.race<boolean>([
|
||||
new Promise(resolve => {
|
||||
node.addEventListener("change", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve =>
|
||||
requestAnimationFrame(() => setTimeout(() => resolve(false)))
|
||||
),
|
||||
])
|
||||
),
|
||||
element.press("ArrowUp"),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("should NOT emit a 'change' event when the value changes by programmatic interaction", () => {
|
||||
test("via end key", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-combobox>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTCombobox) => {
|
||||
node.value = "two";
|
||||
});
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
Promise.race<boolean>([
|
||||
new Promise(resolve => {
|
||||
node.addEventListener("change", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve => setTimeout(() => resolve(false), 50)),
|
||||
])
|
||||
),
|
||||
element.press("End"),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBeFalsy();
|
||||
|
||||
await expect(element).toHaveJSProperty("value", "two");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
await element.evaluate((node: FASTCombobox) => {
|
||||
node.value = "two";
|
||||
});
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
Promise.race<boolean>([
|
||||
new Promise(resolve => {
|
||||
node.addEventListener("change", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve =>
|
||||
requestAnimationFrame(() => setTimeout(() => resolve(false)))
|
||||
),
|
||||
])
|
||||
),
|
||||
element.press("End"),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBeFalsy();
|
||||
|
||||
await expect(element).toHaveJSProperty("value", "two");
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("when the owning form's reset() function is invoked", () => {
|
||||
test("should reset the value property to its initial value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset the value property to its initial value", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-combobox value="one">
|
||||
|
@ -408,8 +477,14 @@ test.describe("Combobox", () => {
|
|||
await expect(element).toHaveJSProperty("value", "one");
|
||||
});
|
||||
|
||||
test("should reset its value property to the first option with the `selected` attribute present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset its value property to the first option with the `selected` attribute present", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-combobox>
|
||||
|
@ -439,36 +514,30 @@ test.describe("Combobox", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should focus the control when an associated label is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-combobox>
|
||||
`;
|
||||
});
|
||||
|
||||
test("should focus the control when an associated label is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Skip this test if the browser if ElementInternals isn't supported
|
||||
if (!(await page.evaluate(() => window.hasOwnProperty("ElementInternals")))) {
|
||||
test.skip();
|
||||
}
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-combobox");
|
||||
|
||||
const label = page.locator("label");
|
||||
|
||||
await root.evaluate(
|
||||
(node, { element }) => {
|
||||
const label = document.createElement("label");
|
||||
label.setAttribute("for", "test-combobox");
|
||||
label.textContent = "label";
|
||||
|
||||
element.id = "test-combobox";
|
||||
|
||||
node.append(label);
|
||||
},
|
||||
{ element: await element.evaluateHandle((node: FASTCombobox) => node) }
|
||||
);
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-combobox id="test-combobox">
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-combobox>
|
||||
<label for="test-combobox">label</label>
|
||||
`;
|
||||
});
|
||||
|
||||
await label.click();
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import { autoUpdate, computePosition, flip, hide, size } from "@floating-ui/dom";
|
||||
import {
|
||||
autoUpdate,
|
||||
computePosition,
|
||||
ElementRects,
|
||||
flip,
|
||||
hide,
|
||||
size,
|
||||
} from "@floating-ui/dom";
|
||||
import { attr, Observable, observable, Updates } from "@microsoft/fast-element";
|
||||
import { limit, uniqueId } from "@microsoft/fast-web-utilities";
|
||||
import type { StaticallyComposableHTML } from "../utilities/template-helpers.js";
|
||||
import type { FASTListboxOption } from "../listbox-option/listbox-option.js";
|
||||
import { DelegatesARIAListbox } from "../listbox/listbox.js";
|
||||
import { StartEnd } from "../patterns/start-end.js";
|
||||
import type { StartEndOptions } from "../patterns/start-end.js";
|
||||
import { StartEnd } from "../patterns/start-end.js";
|
||||
import { applyMixins } from "../utilities/apply-mixins.js";
|
||||
import type { StaticallyComposableHTML } from "../utilities/template-helpers.js";
|
||||
import { FormAssociatedCombobox } from "./combobox.form-associated.js";
|
||||
import { ComboboxAutocomplete } from "./combobox.options.js";
|
||||
|
||||
|
@ -596,7 +603,13 @@ export class FASTCombobox extends FormAssociatedCombobox {
|
|||
middleware: [
|
||||
flip(),
|
||||
size({
|
||||
apply: ({ availableHeight, rects }) => {
|
||||
apply: ({
|
||||
availableHeight,
|
||||
rects,
|
||||
}: {
|
||||
availableHeight: number;
|
||||
rects: ElementRects;
|
||||
}) => {
|
||||
Object.assign(this.listbox.style, {
|
||||
maxHeight: `${availableHeight}px`,
|
||||
width: `${rects.reference.width}px`,
|
||||
|
|
|
@ -146,9 +146,9 @@ export const myDataGrid = DataGrid.compose({
|
|||
|
||||
### Functions
|
||||
|
||||
| Name | Description | Parameters | Return |
|
||||
| -------------------------------- | ----------- | ------------------------ | --------------------- |
|
||||
| `defaultCellFocusTargetCallback` | | `cell: FASTDataGridCell` | `HTMLElement or null` |
|
||||
| Name | Description | Parameters | Return |
|
||||
| -------------------------------- | ------------------------------------------------------------------- | ------------------------ | ------ |
|
||||
| `defaultCellFocusTargetCallback` | Basic focusTargetCallback that returns the first child of the cell. | `cell: FASTDataGridCell` | |
|
||||
|
||||
<hr/>
|
||||
|
||||
|
|
|
@ -1,32 +1,16 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTDataGridCell } from "./data-grid-cell.js";
|
||||
import { DataGridCellTypes } from "./data-grid.options.js";
|
||||
|
||||
declare const FAST: any;
|
||||
|
||||
test.describe("Data grid cell", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test('should set the `role` attribute to "gridcell" by default', async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
element = page.locator("fast-data-grid-cell");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("data-grid-data-grid-cell--data-grid-cell"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test('should set the `role` attribute to "gridcell" by default', async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -35,8 +19,12 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveAttribute("role", "gridcell");
|
||||
});
|
||||
|
||||
test("should have a tabIndex of -1 by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a tabIndex of -1 by default", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -45,8 +33,14 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test('should set the `role` attribute to "columnheader" when the `cell-type` attribute is "columnheader"', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the `role` attribute to "columnheader" when the `cell-type` attribute is "columnheader"', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell cell-type="columnheader"></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -55,8 +49,14 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveAttribute("role", "columnheader");
|
||||
});
|
||||
|
||||
test('should set the `role` attribute to "rowheader" when the `cell-type` attribute is "rowheader"', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the `role` attribute to "rowheader" when the `cell-type` attribute is "rowheader"', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell cell-type="rowheader"></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -65,8 +65,14 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveAttribute("role", "rowheader");
|
||||
});
|
||||
|
||||
test("should set the `grid-column` CSS property to match the `grid-column` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `grid-column` CSS property to match the `grid-column` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell grid-column="2"></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -77,8 +83,12 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveCSS("grid-column-end", "auto");
|
||||
});
|
||||
|
||||
test("should not render data if no columndefinition provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not render data if no columndefinition provided", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -96,8 +106,12 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toBeEmpty();
|
||||
});
|
||||
|
||||
test("should render data when a column definition is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render data when a column definition is provided", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -116,8 +130,12 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveText("data grid cell value 1");
|
||||
});
|
||||
|
||||
test("should render a custom cell template when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render a custom cell template when provided", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -133,8 +151,12 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveText("custom cell template");
|
||||
});
|
||||
|
||||
test("should render a custom header cell template if provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render a custom header cell template if provided", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell cell-type="columnheader"></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -150,8 +172,12 @@ test.describe("Data grid cell", () => {
|
|||
await expect(element).toHaveText("custom header cell template");
|
||||
});
|
||||
|
||||
test(`should fire a "cell-focused" event when focused`, async () => {
|
||||
await root.evaluate(node => {
|
||||
test(`should fire a "cell-focused" event when focused`, async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -169,8 +195,14 @@ test.describe("Data grid cell", () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should focus on custom cell template when a focus target callback is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should focus on custom cell template when a focus target callback is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
`;
|
||||
|
@ -192,8 +224,14 @@ test.describe("Data grid cell", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should focus on custom header cell template when a focus target callback is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should focus on custom header cell template when a focus target callback is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-cell");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-cell cell-type="columnheader"></fast-data-grid-cell>
|
||||
`;
|
||||
|
|
|
@ -44,7 +44,14 @@ const defaultHeaderCellContentsTemplate: ViewTemplate<FASTDataGridCell> = html`
|
|||
</template>
|
||||
`;
|
||||
|
||||
// basic focusTargetCallback that returns the first child of the cell
|
||||
/**
|
||||
* Basic focusTargetCallback that returns the first child of the cell.
|
||||
*
|
||||
* @param cell - the cell to return the focus target for
|
||||
* @returns the first focusable element in the cell
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const defaultCellFocusTargetCallback = (
|
||||
cell: FASTDataGridCell
|
||||
): HTMLElement | null => {
|
||||
|
|
|
@ -1,31 +1,15 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTDataGridRow } from "./data-grid-row.js";
|
||||
|
||||
test.describe("DataGridRow", () => {
|
||||
const cellQueryString = "fast-data-grid-cell";
|
||||
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test('should set the `role` attribute to "row" by default', async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
element = page.locator("fast-data-grid-row");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("data-grid-data-grid-row--data-grid-row"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test('should set the `role` attribute to "row" by default', async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row></fast-data-grid-row>
|
||||
`;
|
||||
|
@ -34,8 +18,14 @@ test.describe("DataGridRow", () => {
|
|||
await expect(element).toHaveAttribute("role", "row");
|
||||
});
|
||||
|
||||
test("should set `grid-template-columns` style to match attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `grid-template-columns` style to match attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row grid-template-columns="1fr 2fr 3fr"></fast-data-grid-row>
|
||||
`;
|
||||
|
@ -47,8 +37,12 @@ test.describe("DataGridRow", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should fire an event when a child cell is focused", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire an event when a child cell is focused", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row>
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
|
@ -74,8 +68,12 @@ test.describe("DataGridRow", () => {
|
|||
expect(wasFocused).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should move focus with left/right arrow key strokes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus with left/right arrow key strokes", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row>
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
|
@ -98,8 +96,14 @@ test.describe("DataGridRow", () => {
|
|||
await expect(element).toHaveJSProperty("focusColumnIndex", 0);
|
||||
});
|
||||
|
||||
test("should move focus to the start/end of the row with home/end keystrokes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus to the start/end of the row with home/end keystrokes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row>
|
||||
<fast-data-grid-cell></fast-data-grid-cell>
|
||||
|
@ -122,10 +126,14 @@ test.describe("DataGridRow", () => {
|
|||
await expect(element).toHaveJSProperty("focusColumnIndex", 0);
|
||||
});
|
||||
|
||||
test("should render no cells if provided no column definitions", async () => {
|
||||
test("should render no cells if provided no column definitions", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
const cells = element.locator("fast-data-grid-cell");
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row></fast-data-grid-row>
|
||||
`;
|
||||
|
@ -141,10 +149,16 @@ test.describe("DataGridRow", () => {
|
|||
await expect(cells).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should render as many column header cells as specified in column definitions", async () => {
|
||||
test("should render as many column header cells as specified in column definitions", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
const cells = element.locator(cellQueryString);
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row></fast-data-grid-row>
|
||||
`;
|
||||
|
@ -176,14 +190,20 @@ test.describe("DataGridRow", () => {
|
|||
await expect(cells).toHaveCount(3);
|
||||
});
|
||||
|
||||
test("should emit a 'rowselectionchange' event when clicked with disableClickSelect disabled", async () => {
|
||||
await root.evaluate((node: FASTDataGridRow) => {
|
||||
test("should emit a 'rowselectionchange' event when clicked with disableClickSelect disabled", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate((node: FASTDataGridRow) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row>
|
||||
<fast-data-grid-cell ></fast-data-grid-cell>
|
||||
</fast-data-grid-row>
|
||||
`;
|
||||
node.disableClickSelect = false;
|
||||
node["disableClickSelect"] = false;
|
||||
});
|
||||
|
||||
const wasInvoked = await Promise.all([
|
||||
|
@ -196,14 +216,20 @@ test.describe("DataGridRow", () => {
|
|||
expect(wasInvoked).toBeTruthy;
|
||||
});
|
||||
|
||||
test("should not emit a 'rowselectionchange' event when clicked with disableClickSelect disabled", async () => {
|
||||
await root.evaluate((node: FASTDataGridRow) => {
|
||||
test("should not emit a 'rowselectionchange' event when clicked with disableClickSelect disabled", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate((node: FASTDataGridRow) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row>
|
||||
<fast-data-grid-cell ></fast-data-grid-cell>
|
||||
</fast-data-grid-row>
|
||||
`;
|
||||
node.disableClickSelect = true;
|
||||
node["disableClickSelect"] = true;
|
||||
});
|
||||
|
||||
const wasInvoked = await Promise.all([
|
||||
|
@ -216,14 +242,20 @@ test.describe("DataGridRow", () => {
|
|||
expect(wasInvoked).toBeFalsy;
|
||||
});
|
||||
|
||||
test("should emit a 'rowselectionchange' event when space key is pressed with disableClickSelect disabled", async () => {
|
||||
await root.evaluate((node: FASTDataGridRow) => {
|
||||
test("should emit a 'rowselectionchange' event when space key is pressed with disableClickSelect disabled", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid-row");
|
||||
|
||||
await page.locator("#root").evaluate((node: FASTDataGridRow) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid-row>
|
||||
<fast-data-grid-cell ></fast-data-grid-cell>
|
||||
</fast-data-grid-row>
|
||||
`;
|
||||
node.disableClickSelect = false;
|
||||
node["disableClickSelect"] = false;
|
||||
});
|
||||
|
||||
const wasInvoked = await Promise.all([
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import type { ViewTemplate } from "@microsoft/fast-element";
|
||||
import {
|
||||
children,
|
||||
elements,
|
||||
|
@ -5,8 +6,8 @@ import {
|
|||
html,
|
||||
slotted,
|
||||
} from "@microsoft/fast-element";
|
||||
import type { ViewTemplate } from "@microsoft/fast-element";
|
||||
import { tagFor, TemplateElementDependency } from "../patterns/index.js";
|
||||
import type { TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
import { tagFor } from "../patterns/tag-for.js";
|
||||
import type { FASTDataGridRow } from "./data-grid-row.js";
|
||||
import type { ColumnDefinition } from "./data-grid.js";
|
||||
|
||||
|
|
|
@ -1,34 +1,18 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTDataGridRow } from "./data-grid-row.js";
|
||||
import type { FASTDataGrid } from "./data-grid.js";
|
||||
import { DataGridRowTypes } from "./data-grid.options.js";
|
||||
|
||||
test.describe("Data grid", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
|
||||
const selectedRowQueryString = '[aria-selected="true"]';
|
||||
const rowQueryString = "fast-data-grid-row";
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
test("should set role to 'grid'", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-data-grid");
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("data-grid--data-grid"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set role to 'grid'", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid></fast-data-grid>
|
||||
`;
|
||||
|
@ -37,8 +21,12 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveAttribute("role", "grid");
|
||||
});
|
||||
|
||||
test("should have a tabIndex of 0 by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a tabIndex of 0 by default", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid></fast-data-grid>
|
||||
`;
|
||||
|
@ -47,8 +35,12 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should have a tabIndex of -1 when no-tabbing is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a tabIndex of -1 when no-tabbing is true", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid no-tabbing></fast-data-grid>
|
||||
`;
|
||||
|
@ -57,8 +49,12 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test("should have a tabIndex of -1 when a cell is focused", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a tabIndex of -1 when a cell is focused", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid>
|
||||
<fast-data-grid-row>
|
||||
|
@ -74,8 +70,14 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test("should generate a basic grid with a row header based on rowsData only", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should generate a basic grid with a row header based on rowsData only", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid></fast-data-grid>
|
||||
`;
|
||||
|
@ -129,8 +131,14 @@ test.describe("Data grid", () => {
|
|||
await expect(row3Cells.nth(1)).toHaveText("Person 2");
|
||||
});
|
||||
|
||||
test("should not generate a header when `generateHeader` is `none`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not generate a header when `generateHeader` is `none`", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none"></fast-data-grid>
|
||||
`;
|
||||
|
@ -172,8 +180,12 @@ test.describe("Data grid", () => {
|
|||
await expect(row2Cells.nth(1)).toHaveText("Person 2");
|
||||
});
|
||||
|
||||
test("should not generate a header when rowsData is empty", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not generate a header when rowsData is empty", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const dataGrid = document.createElement("fast-data-grid") as FASTDataGrid;
|
||||
|
@ -188,8 +200,14 @@ test.describe("Data grid", () => {
|
|||
await expect(rows).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should generate a sticky header when generateHeader is set to 'sticky'", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should generate a sticky header when generateHeader is set to 'sticky'", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="sticky"></fast-data-grid>
|
||||
`;
|
||||
|
@ -243,8 +261,12 @@ test.describe("Data grid", () => {
|
|||
await expect(row3Cells.nth(1)).toHaveText("Person 2");
|
||||
});
|
||||
|
||||
test("should set the row index attribute of child rows'", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the row index attribute of child rows'", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="sticky"></fast-data-grid>
|
||||
`;
|
||||
|
@ -269,8 +291,12 @@ test.describe("Data grid", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should move focus with up/down arrow key strokes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus with up/down arrow key strokes", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none"></fast-data-grid>
|
||||
`;
|
||||
|
@ -317,8 +343,14 @@ test.describe("Data grid", () => {
|
|||
await expect(row2Cells.nth(0)).toBeFocused();
|
||||
});
|
||||
|
||||
test("should move focus to first/last cells with ctrl + home/end key strokes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus to first/last cells with ctrl + home/end key strokes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none"></fast-data-grid>
|
||||
`;
|
||||
|
@ -351,8 +383,14 @@ test.describe("Data grid", () => {
|
|||
await expect(firstCell).toBeFocused();
|
||||
});
|
||||
|
||||
test("should move focus by setting the `focusRowIndex` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus by setting the `focusRowIndex` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none"></fast-data-grid>
|
||||
`;
|
||||
|
@ -393,8 +431,12 @@ test.describe("Data grid", () => {
|
|||
await expect(cells.nth(0)).toBeFocused();
|
||||
});
|
||||
|
||||
test("should move focus by setting `focusColumnIndex`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus by setting `focusColumnIndex`", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none"></fast-data-grid>
|
||||
`;
|
||||
|
@ -435,8 +477,12 @@ test.describe("Data grid", () => {
|
|||
await expect(cells.nth(0)).toBeFocused();
|
||||
});
|
||||
|
||||
test("should scroll into view on focus", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should scroll into view on focus", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" style="height:100px; overflow-y: scroll;">
|
||||
<fast-data-grid-row style="height:100px;">
|
||||
|
@ -461,13 +507,19 @@ test.describe("Data grid", () => {
|
|||
await cells.nth(0).focus();
|
||||
await expect(element).toHaveJSProperty("scrollTop", 0);
|
||||
await cells.nth(1).focus();
|
||||
await expect(element).toHaveJSProperty("scrollTop", 100);
|
||||
expect(await element.evaluate(node => node.scrollTop)).toBeCloseTo(100, -1);
|
||||
await cells.nth(2).focus();
|
||||
await expect(element).toHaveJSProperty("scrollTop", 200);
|
||||
expect(await element.evaluate(node => node.scrollTop)).toBeCloseTo(200, -1);
|
||||
});
|
||||
|
||||
test("should not apply initial selection in default 'none' selection mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not apply initial selection in default 'none' selection mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" initial-row-selection="0" selection-mode="none">
|
||||
<fast-data-grid-row>
|
||||
|
@ -486,8 +538,14 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveJSProperty("selectedRowIndexes", []);
|
||||
});
|
||||
|
||||
test("should apply initial selection in 'single-row' selection mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should apply initial selection in 'single-row' selection mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" initial-row-selection="0" selection-mode="single-row">
|
||||
<fast-data-grid-row>
|
||||
|
@ -506,8 +564,14 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveJSProperty("selectedRowIndexes", [0]);
|
||||
});
|
||||
|
||||
test("should apply initial selection in 'multi-row' selection mode", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should apply initial selection in 'multi-row' selection mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" initial-row-selection="0,1" selection-mode="multi-row">
|
||||
<fast-data-grid-row>
|
||||
|
@ -526,10 +590,16 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveJSProperty("selectedRowIndexes", [0, 1]);
|
||||
});
|
||||
|
||||
test("should apply user set selection in 'single-row' selection mode", async () => {
|
||||
test("should apply user set selection in 'single-row' selection mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" initial-row-selection="0" selection-mode="single-row">
|
||||
<fast-data-grid-row>
|
||||
|
@ -561,10 +631,16 @@ test.describe("Data grid", () => {
|
|||
await expect(selectedRows).toHaveCount(1);
|
||||
});
|
||||
|
||||
test("should apply user set selection in 'multi-row' selection mode", async () => {
|
||||
test("should apply user set selection in 'multi-row' selection mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" initial-row-selection="0" selection-mode="multi-row">
|
||||
<fast-data-grid-row>
|
||||
|
@ -596,10 +672,14 @@ test.describe("Data grid", () => {
|
|||
await expect(selectedRows).toHaveCount(3);
|
||||
});
|
||||
|
||||
test("should not allow selection of header row by default", async () => {
|
||||
test("should not allow selection of header row by default", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" initial-row-selection="0" selection-mode="single-row">
|
||||
<fast-data-grid-row row-type="header">
|
||||
|
@ -619,13 +699,18 @@ test.describe("Data grid", () => {
|
|||
await expect(selectedRows).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should select and deselect rows with space bar + shift keys", async () => {
|
||||
test("should select and deselect rows with space bar + shift keys", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
const rows = element.locator(rowQueryString);
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0);
|
||||
const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2);
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" selection-mode="single-row"></fast-data-grid>
|
||||
`;
|
||||
|
@ -653,13 +738,16 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveJSProperty("selectedRowIndexes", [2]);
|
||||
});
|
||||
|
||||
test("should select and deselect rows with a click", async () => {
|
||||
test("should select and deselect rows with a click", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
const rows = element.locator(rowQueryString);
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0);
|
||||
const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2);
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" selection-mode="single-row"></fast-data-grid>
|
||||
`;
|
||||
|
@ -685,13 +773,17 @@ test.describe("Data grid", () => {
|
|||
await expect(element).toHaveJSProperty("selectedRowIndexes", [2]);
|
||||
});
|
||||
|
||||
test("should select/deselect all in row multi-select with a ctrl + a", async () => {
|
||||
test("should select/deselect all in row multi-select with a ctrl + a", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
const rows = element.locator(rowQueryString);
|
||||
const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0);
|
||||
await firstCell.focus();
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" selection-mode="multi-row"></fast-data-grid>
|
||||
`;
|
||||
|
@ -713,14 +805,18 @@ test.describe("Data grid", () => {
|
|||
await expect(selectedRows).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should select/deselect multiple rows with shift key in multi-select mode", async () => {
|
||||
test("should select/deselect multiple rows with shift key in multi-select mode", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
const selectedRows = element.locator(selectedRowQueryString);
|
||||
const rows = element.locator(rowQueryString);
|
||||
const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0);
|
||||
const lastCell = rows.nth(2).locator("fast-data-grid-cell").nth(2);
|
||||
await firstCell.focus();
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" selection-mode="multi-row"></fast-data-grid>
|
||||
`;
|
||||
|
@ -742,12 +838,14 @@ test.describe("Data grid", () => {
|
|||
await expect(selectedRows).toHaveCount(2);
|
||||
});
|
||||
|
||||
test("should emit an event when row selection changes", async () => {
|
||||
test("should emit an event when row selection changes", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-data-grid");
|
||||
const rows = element.locator(rowQueryString);
|
||||
const firstCell = rows.nth(0).locator("fast-data-grid-cell").nth(0);
|
||||
await firstCell.focus();
|
||||
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-data-grid generate-header="none" selection-mode="multi-row"></fast-data-grid>
|
||||
`;
|
||||
|
@ -761,6 +859,8 @@ test.describe("Data grid", () => {
|
|||
];
|
||||
});
|
||||
|
||||
await firstCell.focus();
|
||||
|
||||
const wasInvoked = await Promise.all([
|
||||
element.evaluate(node =>
|
||||
node.addEventListener("selectionchange", () => true)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { children, elements, ElementViewTemplate, html } from "@microsoft/fast-element";
|
||||
import type { ViewTemplate } from "@microsoft/fast-element";
|
||||
import { tagFor, TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
import { children, elements, ElementViewTemplate, html } from "@microsoft/fast-element";
|
||||
import type { TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
import { tagFor } from "../patterns/tag-for.js";
|
||||
import type { FASTDataGrid } from "./data-grid.js";
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
export { DataGridOptions, dataGridTemplate } from "./data-grid.template.js";
|
||||
export { FASTDataGridCell } from "./data-grid-cell.js";
|
||||
export type {
|
||||
DataGridCellTypes,
|
||||
defaultCellFocusTargetCallback,
|
||||
} from "./data-grid-cell.js";
|
||||
export { dataGridCellTemplate } from "./data-grid-cell.template.js";
|
||||
export { FASTDataGridRow } from "./data-grid-row.js";
|
||||
export { dataGridRowTemplate } from "./data-grid-row.template.js";
|
||||
export type { CellItemTemplateOptions } from "./data-grid-row.template.js";
|
||||
export {
|
||||
ColumnDefinition,
|
||||
DataGridRowTypes,
|
||||
|
@ -7,14 +15,5 @@ export {
|
|||
FASTDataGrid,
|
||||
GenerateHeaderOptions,
|
||||
} from "./data-grid.js";
|
||||
export {
|
||||
dataGridRowTemplate,
|
||||
CellItemTemplateOptions,
|
||||
} from "./data-grid-row.template.js";
|
||||
export { FASTDataGridRow } from "./data-grid-row.js";
|
||||
export { dataGridCellTemplate } from "./data-grid-cell.template.js";
|
||||
export {
|
||||
DataGridCellTypes,
|
||||
defaultCellFocusTargetCallback,
|
||||
FASTDataGridCell,
|
||||
} from "./data-grid-cell.js";
|
||||
export { dataGridTemplate } from "./data-grid.template.js";
|
||||
export type { DataGridOptions } from "./data-grid.template.js";
|
||||
|
|
|
@ -5,9 +5,7 @@ import type {
|
|||
Observable as FASTObservable,
|
||||
Updates as FASTUpdates,
|
||||
} from "@microsoft/fast-element";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { DesignTokenResolver } from "./core/design-token-node.js";
|
||||
import type {
|
||||
CSSDesignToken as CSSDesignTokenImpl,
|
||||
|
@ -48,26 +46,21 @@ function uniqueTokenName(): string {
|
|||
// Test utilities
|
||||
|
||||
test.describe("A DesignToken", () => {
|
||||
let page: Page;
|
||||
let root: Locator;
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("debug-designtoken--design-token"));
|
||||
await page.evaluate(() => DesignToken.registerDefaultStyleTarget());
|
||||
});
|
||||
test.afterAll(async () => {
|
||||
await page.evaluate(() => DesignToken.registerDefaultStyleTarget());
|
||||
await page.close();
|
||||
await page.evaluate(() => {
|
||||
DesignToken.registerDefaultStyleTarget();
|
||||
});
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await page.evaluate(() => cleanup());
|
||||
test.afterEach(async ({ page }) => {
|
||||
await page.evaluate(() => {
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
|
||||
test("should support declared types", async () => {
|
||||
test("should support declared types", async ({ page }) => {
|
||||
await page.evaluate((name: string) => {
|
||||
const number = DesignToken.create<number>(name);
|
||||
const nil = DesignToken.create<null>(name);
|
||||
|
@ -81,7 +74,15 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("should have a create method", () => {
|
||||
test("that creates a CSSDesignToken when invoked with a string value", async () => {
|
||||
test("that creates a CSSDesignToken when invoked with a string value", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.evaluate(() => {
|
||||
DesignToken.registerDefaultStyleTarget();
|
||||
});
|
||||
|
||||
const result = await page.evaluate(
|
||||
(name: string) => DesignToken.create(name) instanceof CSSDesignToken,
|
||||
uniqueTokenName()
|
||||
|
@ -89,7 +90,16 @@ test.describe("A DesignToken", () => {
|
|||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
test("that creates a CSSDesignToken when invoked with a CSSDesignTokenConfiguration", async () => {
|
||||
|
||||
test("that creates a CSSDesignToken when invoked with a CSSDesignTokenConfiguration", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.evaluate(() => {
|
||||
DesignToken.registerDefaultStyleTarget();
|
||||
});
|
||||
|
||||
const result = await page.evaluate(
|
||||
(name: string) =>
|
||||
DesignToken.create({
|
||||
|
@ -100,25 +110,31 @@ test.describe("A DesignToken", () => {
|
|||
);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
test("that creates a DesignToken when invoked with a DesignTokenConfiguration", async () => {
|
||||
const result = await page.evaluate(
|
||||
(name: string) => DesignToken.create({ name }) instanceof CSSDesignToken,
|
||||
uniqueTokenName()
|
||||
);
|
||||
|
||||
test("that creates a DesignToken when invoked with a DesignTokenConfiguration", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const result = await page.evaluate((name: string) => {
|
||||
DesignToken.registerDefaultStyleTarget();
|
||||
const token = DesignToken.create({ name });
|
||||
return token instanceof CSSDesignToken;
|
||||
}, uniqueTokenName());
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("that is not a CSSDesignToken", () => {
|
||||
test("should not have a cssCustomProperty property", async () => {
|
||||
test("should not have a cssCustomProperty property", async ({ page }) => {
|
||||
const result = await page.evaluate((name: string) => {
|
||||
return "cssCustomProperty" in DesignToken.create<number>({ name });
|
||||
}, uniqueTokenName());
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
test("should not have a cssVar property", async () => {
|
||||
test("should not have a cssVar property", async ({ page }) => {
|
||||
const result = await page.evaluate((name: string) => {
|
||||
return "cssVar" in DesignToken.create<number>({ name });
|
||||
}, uniqueTokenName());
|
||||
|
@ -126,7 +142,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
test.describe("getting and setting a simple value", () => {
|
||||
test("should throw if the token value has never been set on the element or its ancestors", async () => {
|
||||
test("should throw if the token value has never been set on the element or its ancestors", async ({
|
||||
page,
|
||||
}) => {
|
||||
const result = await page.evaluate((name: string) => {
|
||||
const target = addElement();
|
||||
const token = DesignToken.create<number>(name);
|
||||
|
@ -136,7 +154,9 @@ test.describe("A DesignToken", () => {
|
|||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("should return the value set for the element if one has been set", async () => {
|
||||
test("should return the value set for the element if one has been set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const result = await page.evaluate((name: string) => {
|
||||
const target = addElement();
|
||||
const token = DesignToken.create<number>(name);
|
||||
|
@ -147,7 +167,9 @@ test.describe("A DesignToken", () => {
|
|||
expect(result).toEqual(12);
|
||||
});
|
||||
|
||||
test("should return the value set for an ancestor if a value has not been set for the target", async () => {
|
||||
test("should return the value set for an ancestor if a value has not been set for the target", async ({
|
||||
page,
|
||||
}) => {
|
||||
const result = await page.evaluate((name: string) => {
|
||||
const ancestor = addElement();
|
||||
const target = addElement(ancestor);
|
||||
|
@ -159,7 +181,9 @@ test.describe("A DesignToken", () => {
|
|||
expect(result).toEqual(12);
|
||||
});
|
||||
|
||||
test("sound return the nearest ancestor's value after an intermediary value is set where no value was set prior", async () => {
|
||||
test("sound return the nearest ancestor's value after an intermediary value is set where no value was set prior", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -179,7 +203,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([12, 14]);
|
||||
});
|
||||
|
||||
test("should return the new ancestor's value after being re-parented", async () => {
|
||||
test("should return the new ancestor's value after being re-parented", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -202,7 +228,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([12, 14]);
|
||||
});
|
||||
|
||||
test("should persist explicitly set value even if it matches the inherited value", async () => {
|
||||
test("should persist explicitly set value even if it matches the inherited value", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -224,7 +252,7 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([12, 12]);
|
||||
});
|
||||
|
||||
test("should support getting and setting falsey values", async () => {
|
||||
test("should support getting and setting falsey values", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -250,7 +278,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("that is a CSSDesignToken", () => {
|
||||
test("should set the CSS custom property for the element", async () => {
|
||||
test("should set the CSS custom property for the element", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const target = addElement();
|
||||
|
@ -263,7 +293,7 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe("12");
|
||||
});
|
||||
test("should be a CSSDirective", async () => {
|
||||
test("should be a CSSDirective", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const token = DesignToken.create<number>(
|
||||
|
@ -286,7 +316,7 @@ test.describe("A DesignToken", () => {
|
|||
).toBe("12");
|
||||
});
|
||||
|
||||
test("should inherit CSS custom property from ancestor", async () => {
|
||||
test("should inherit CSS custom property from ancestor", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -312,7 +342,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", "14"]);
|
||||
});
|
||||
|
||||
test("should set CSS custom property for element if value stops matching inherited value", async () => {
|
||||
test("should set CSS custom property for element if value stops matching inherited value", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -340,7 +372,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
test.describe("that is not a CSSDesignToken", () => {
|
||||
test("should not set a CSS custom property for the element", async () => {
|
||||
test("should not set a CSS custom property for the element", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const name = uniqueTokenName();
|
||||
|
@ -357,7 +391,7 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("getting and setting derived values", () => {
|
||||
test("should get the return value of a derived value", async () => {
|
||||
test("should get the return value of a derived value", async ({ page }) => {
|
||||
const name = uniqueTokenName();
|
||||
expect(
|
||||
await page.evaluate((name: string) => {
|
||||
|
@ -369,7 +403,9 @@ test.describe("A DesignToken", () => {
|
|||
}, name)
|
||||
).toBe(12);
|
||||
});
|
||||
test("should get an updated value when observable properties used in a derived property are changed", async () => {
|
||||
test("should get an updated value when observable properties used in a derived property are changed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const name = uniqueTokenName();
|
||||
expect(
|
||||
await page.evaluate(async (name: string) => {
|
||||
|
@ -392,7 +428,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([12, 14]);
|
||||
});
|
||||
|
||||
test("should get an updated value when other design tokens used in a derived property are changed", async () => {
|
||||
test("should get an updated value when other design tokens used in a derived property are changed", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const target = addElement();
|
||||
|
@ -412,7 +450,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual([12, 14]);
|
||||
});
|
||||
test("should use the closest value of a dependent token when getting a token for a target", async () => {
|
||||
test("should use the closest value of a dependent token when getting a token for a target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const ancestor = addElement();
|
||||
|
@ -430,7 +470,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe(12);
|
||||
});
|
||||
|
||||
test("should update value of a dependent token when getting a token for a target", async () => {
|
||||
test("should update value of a dependent token when getting a token for a target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -455,7 +497,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([12, 14]);
|
||||
});
|
||||
|
||||
test("should get an updated value when a used design token is set for a node closer to the target", async () => {
|
||||
test("should get an updated value when a used design token is set for a node closer to the target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -479,7 +523,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("that is a CSSDesignToken", () => {
|
||||
test("should set a CSS custom property equal to the resolved value of a derived token value", async () => {
|
||||
test("should set a CSS custom property equal to the resolved value of a derived token value", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const target = addElement();
|
||||
|
@ -494,7 +540,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe("12");
|
||||
});
|
||||
test("should set a CSS custom property equal to the resolved value of a derived token value with a dependent token", async () => {
|
||||
test("should set a CSS custom property equal to the resolved value of a derived token value with a dependent token", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const target = addElement();
|
||||
|
@ -513,7 +561,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe("12");
|
||||
});
|
||||
|
||||
test("should update a CSS custom property to the resolved value of a derived token value with a dependent token when the dependent token changes", async () => {
|
||||
test("should update a CSS custom property to the resolved value of a derived token value with a dependent token when the dependent token changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -544,7 +594,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", "14"]);
|
||||
});
|
||||
|
||||
test("should set a CSS custom property equal to the resolved value for an element of a derived token value with a dependent token", async () => {
|
||||
test("should set a CSS custom property equal to the resolved value for an element of a derived token value with a dependent token", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -574,7 +626,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", "14"]);
|
||||
});
|
||||
|
||||
test("should set a CSS custom property equal to the resolved value for an element in a shadow DOM of a derived token value with a dependent token", async () => {
|
||||
test("should set a CSS custom property equal to the resolved value for an element in a shadow DOM of a derived token value with a dependent token", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -606,7 +660,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", "14"]);
|
||||
});
|
||||
|
||||
test("should set a CSS custom property equal to the resolved value for both elements for which a dependent token is set when setting a derived token value", async () => {
|
||||
test("should set a CSS custom property equal to the resolved value for both elements for which a dependent token is set when setting a derived token value", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -636,7 +692,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", "14"]);
|
||||
});
|
||||
|
||||
test("should revert a CSS custom property back to a previous value when the Design Token value is reverted", async () => {
|
||||
test("should revert a CSS custom property back to a previous value when the Design Token value is reverted", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -674,7 +732,7 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("that is not a CSSDesignToken", () => {
|
||||
test("should not emit a CSS custom property", async () => {
|
||||
test("should not emit a CSS custom property", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -692,7 +750,7 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should support getting and setting falsey values", async () => {
|
||||
test("should support getting and setting falsey values", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -718,7 +776,7 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("getting and setting a token value", () => {
|
||||
test("should retrieve the value of the token it was set to", async () => {
|
||||
test("should retrieve the value of the token it was set to", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const tokenA = DesignToken.create<number>(uniqueTokenName());
|
||||
|
@ -733,7 +791,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe(12);
|
||||
});
|
||||
|
||||
test("should update the value of the token it was set to when the token's value changes", async () => {
|
||||
test("should update the value of the token it was set to when the token's value changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -753,7 +813,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual([12, 14]);
|
||||
});
|
||||
test("should update the derived value of the token when a dependency of the derived value changes", async () => {
|
||||
test("should update the derived value of the token when a dependency of the derived value changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -778,7 +840,7 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("that is a CSSDesignToken", () => {
|
||||
test("should emit a CSS custom property", async () => {
|
||||
test("should emit a CSS custom property", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const tokenA = DesignToken.create<number>("token-a");
|
||||
|
@ -795,7 +857,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
);
|
||||
});
|
||||
test("should update the emitted CSS custom property when the token's value changes", async () => {
|
||||
test("should update the emitted CSS custom property when the token's value changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -827,7 +891,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual(["12", "14"]);
|
||||
});
|
||||
test("should update the emitted CSS custom property of a token assigned a derived value when the token dependency changes", async () => {
|
||||
test("should update the emitted CSS custom property of a token assigned a derived value when the token dependency changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -861,7 +927,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", "14"]);
|
||||
});
|
||||
|
||||
test("should support accessing the token being assigned from the derived value, resolving to a parent value", async () => {
|
||||
test("should support accessing the token being assigned from the derived value, resolving to a parent value", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -881,7 +949,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([12, 24]);
|
||||
});
|
||||
});
|
||||
test("should update the CSS custom property of a derived token with a dependency that is a derived token that depends on a third token", async () => {
|
||||
test("should update the CSS custom property of a derived token with a dependency that is a derived token that depends on a third token", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -921,7 +991,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
test.describe("deleting simple values", () => {
|
||||
test("should throw when deleted and no parent token value is set", async () => {
|
||||
test("should throw when deleted and no parent token value is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results = [];
|
||||
|
@ -939,7 +1011,7 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual([12, true]);
|
||||
});
|
||||
test("should allow getting a value that was set upstream", async () => {
|
||||
test("should allow getting a value that was set upstream", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results = [];
|
||||
|
@ -961,7 +1033,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
test.describe("deleting derived values", () => {
|
||||
test("should throw when deleted and no parent token value is set", async () => {
|
||||
test("should throw when deleted and no parent token value is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results = [];
|
||||
|
@ -979,7 +1053,7 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual([12, true]);
|
||||
});
|
||||
test("should allow getting a value that was set upstream", async () => {
|
||||
test("should allow getting a value that was set upstream", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results = [];
|
||||
|
@ -1000,7 +1074,7 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([14, 12]);
|
||||
});
|
||||
|
||||
test("should cause dependent tokens to re-evaluate", async () => {
|
||||
test("should cause dependent tokens to re-evaluate", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results = [];
|
||||
|
@ -1024,7 +1098,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
test.describe("when used as a CSSDirective", () => {
|
||||
test("should set a CSS custom property for the element when the token is set for the element", async () => {
|
||||
test("should set a CSS custom property for the element when the token is set for the element", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const target = addElement();
|
||||
|
@ -1042,7 +1118,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe("12px");
|
||||
});
|
||||
test("should set a CSS custom property for the element when the token is set for an ancestor element", async () => {
|
||||
test("should set a CSS custom property for the element when the token is set for an ancestor element", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const parent = addElement();
|
||||
|
@ -1064,7 +1142,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("with a default value set", () => {
|
||||
test("should return the default value if no value is set for a target", async () => {
|
||||
test("should return the default value if no value is set for a target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -1074,7 +1154,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(2);
|
||||
});
|
||||
test("should return the default value for a descendent if no value is set for a target", async () => {
|
||||
test("should return the default value for a descendent if no value is set for a target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const parent = addElement();
|
||||
|
@ -1086,7 +1168,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(2);
|
||||
});
|
||||
test("should return the value set and not the default if value is set", async () => {
|
||||
test("should return the value set and not the default if value is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -1098,7 +1182,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(2);
|
||||
});
|
||||
test("should get a new default value if a new default is provided", async () => {
|
||||
test("should get a new default value if a new default is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -1110,7 +1196,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(4);
|
||||
});
|
||||
test("should return the default value if retrieved for an element that has not been connected", async () => {
|
||||
test("should return the default value if retrieved for an element that has not been connected", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const token = DesignToken.create<number>(
|
||||
|
@ -1122,7 +1210,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(12);
|
||||
});
|
||||
test("should set a derived value that uses a token's default value prior to connection", async () => {
|
||||
test("should set a derived value that uses a token's default value prior to connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const dependency = DesignToken.create<number>(
|
||||
|
@ -1137,7 +1227,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(false);
|
||||
});
|
||||
test("should delete a derived value that uses a token's default value prior to connection", async () => {
|
||||
test("should delete a derived value that uses a token's default value prior to connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const dependency = DesignToken.create<number>(
|
||||
|
@ -1154,7 +1246,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("with subscribers", () => {
|
||||
test("should notify an un-targeted subscriber when the value changes for any element", async () => {
|
||||
test("should notify an un-targeted subscriber when the value changes for any element", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results: any = [];
|
||||
|
@ -1200,7 +1294,9 @@ test.describe("A DesignToken", () => {
|
|||
[true, true, true],
|
||||
]);
|
||||
});
|
||||
test("should notify a target-subscriber if the value is changed for the provided target", async () => {
|
||||
test("should notify a target-subscriber if the value is changed for the provided target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const results = [];
|
||||
|
@ -1225,7 +1321,7 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
test("should not notify a subscriber after unsubscribing", async () => {
|
||||
test("should not notify a subscriber after unsubscribing", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const target = addElement();
|
||||
|
@ -1245,7 +1341,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe(0);
|
||||
});
|
||||
|
||||
test("should infer DesignToken and CSSDesignToken token types on subscription record", async () => {
|
||||
test("should infer DesignToken and CSSDesignToken token types on subscription record", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.evaluate(() => {
|
||||
type AssertCSSDesignToken<T> = T extends CSSDesignTokenImpl<any>
|
||||
? T
|
||||
|
@ -1267,7 +1365,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should notify a subscriber when a dependency of a subscribed token changes", async () => {
|
||||
test("should notify a subscriber when a dependency of a subscribed token changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const tokenA = DesignToken.create<number>(uniqueTokenName());
|
||||
|
@ -1290,7 +1390,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe(1);
|
||||
});
|
||||
|
||||
test("should notify a subscriber when a dependency of a dependency of a subscribed token changes", async () => {
|
||||
test("should notify a subscriber when a dependency of a dependency of a subscribed token changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const tokenA = DesignToken.create<number>(uniqueTokenName());
|
||||
|
@ -1315,7 +1417,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe(1);
|
||||
});
|
||||
|
||||
test("should notify a subscriber when a dependency changes for an element down the DOM tree", async () => {
|
||||
test("should notify a subscriber when a dependency changes for an element down the DOM tree", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const tokenA = DesignToken.create<number>(uniqueTokenName());
|
||||
|
@ -1339,7 +1443,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe(1);
|
||||
});
|
||||
test("should notify a subscriber when a static-value dependency of subscribed token changes for a parent of the subscription target", async () => {
|
||||
test("should notify a subscriber when a static-value dependency of subscribed token changes for a parent of the subscription target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -1368,7 +1474,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual([1, 14]);
|
||||
});
|
||||
test("should notify a subscriber when a derived-value dependency of subscribed token changes for a parent of the subscription target", async () => {
|
||||
test("should notify a subscriber when a derived-value dependency of subscribed token changes for a parent of the subscription target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -1396,7 +1504,9 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toEqual([1, 14]);
|
||||
});
|
||||
test("should notify a subscriber when a dependency of subscribed token changes for a parent of the subscription target", async () => {
|
||||
test("should notify a subscriber when a dependency of subscribed token changes for a parent of the subscription target", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const tokenA = DesignToken.create<number>(uniqueTokenName());
|
||||
|
@ -1425,7 +1535,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
test.describe("with root registration", () => {
|
||||
test("should not emit CSS custom properties for the default value if a root is not registered", async () => {
|
||||
test("should not emit CSS custom properties for the default value if a root is not registered", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
DesignToken.unregisterDefaultStyleTarget();
|
||||
|
@ -1439,7 +1551,9 @@ test.describe("A DesignToken", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should emit CSS custom properties for the default value when a design token root is registered", async () => {
|
||||
test("should emit CSS custom properties for the default value when a design token root is registered", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const token = DesignToken.create<number>(
|
||||
|
@ -1456,7 +1570,9 @@ test.describe("A DesignToken", () => {
|
|||
).toBe("12");
|
||||
});
|
||||
|
||||
test("should remove emitted CSS custom properties for a root when the root is deregistered", async () => {
|
||||
test("should remove emitted CSS custom properties for a root when the root is deregistered", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [];
|
||||
|
@ -1480,7 +1596,9 @@ test.describe("A DesignToken", () => {
|
|||
).toEqual(["12", ""]);
|
||||
});
|
||||
|
||||
test("should emit CSS custom properties to an element when the element is provided as a root", async () => {
|
||||
test("should emit CSS custom properties to an element when the element is provided as a root", async ({
|
||||
page,
|
||||
}) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const token = DesignToken.create<number>(
|
||||
|
@ -1497,7 +1615,7 @@ test.describe("A DesignToken", () => {
|
|||
})
|
||||
).toBe("12");
|
||||
});
|
||||
test("should emit CSS custom properties to multiple roots", async () => {
|
||||
test("should emit CSS custom properties to multiple roots", async ({ page }) => {
|
||||
expect(
|
||||
await page.evaluate(async () => {
|
||||
const results = [] as any;
|
||||
|
@ -1545,7 +1663,9 @@ test.describe("A DesignToken", () => {
|
|||
});
|
||||
|
||||
// Flakey and seems to be corrupted by other tests.
|
||||
test.skip("should set properties for a PropertyTarget registered as the root", async () => {
|
||||
test("should set properties for a PropertyTarget registered as the root", async ({
|
||||
page,
|
||||
}) => {
|
||||
const results = await page.evaluate(async () => {
|
||||
const results = [];
|
||||
const token = DesignToken.create<number>(uniqueTokenName()).withDefault(
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
import { css, FASTElement, html, Observable, Updates } from "@microsoft/fast-element";
|
||||
import { uniqueElementName } from "@microsoft/fast-element/testing.js";
|
||||
import { CSSDesignToken, DesignToken as FASTDesignToken } from "../fast-design-token.js";
|
||||
|
||||
const controllerElementName = uniqueElementName("design-token-controller");
|
||||
const fixtureElementName = uniqueElementName("design-token-fixture");
|
||||
|
||||
// Define element that can have token mutated for it
|
||||
(class extends FASTElement {}).define({
|
||||
name: fixtureElementName,
|
||||
template: html`
|
||||
<slot></slot>
|
||||
`,
|
||||
});
|
||||
|
||||
const elementCache = new Set<HTMLElement>();
|
||||
// The objects required for unit-testing
|
||||
// DesignToken. These get installed on the
|
||||
// globalThis during story connection, and
|
||||
// removed during disconnection
|
||||
const requiredTestObject = {
|
||||
DesignToken: FASTDesignToken,
|
||||
CSSDesignToken,
|
||||
uniqueTokenName() {
|
||||
return uniqueElementName() + "token";
|
||||
},
|
||||
createElement(): FASTElement {
|
||||
const element = document.createElement(fixtureElementName) as FASTElement;
|
||||
elementCache.add(element);
|
||||
return element;
|
||||
},
|
||||
addElement(parent = document.body) {
|
||||
const el = requiredTestObject.createElement();
|
||||
el.setAttribute("id", "id" + uniqueElementName());
|
||||
parent.appendChild(el);
|
||||
return el;
|
||||
},
|
||||
css,
|
||||
threw(fn: () => void): boolean {
|
||||
try {
|
||||
fn();
|
||||
return false;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
spy(fn: () => any) {
|
||||
let calls: number = 0;
|
||||
const callArgs: any = [];
|
||||
const f = (...args: any[]) => {
|
||||
calls += 1;
|
||||
callArgs[calls] = args;
|
||||
};
|
||||
Object.defineProperties(f, {
|
||||
calls: {
|
||||
get() {
|
||||
return calls;
|
||||
},
|
||||
},
|
||||
calledWith: {
|
||||
value: function (n: number): any {
|
||||
return callArgs[n];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return f;
|
||||
},
|
||||
Updates,
|
||||
Observable,
|
||||
cleanup() {
|
||||
elementCache.forEach(value => {
|
||||
value.parentElement?.removeChild(value);
|
||||
elementCache.delete(value);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
(class extends FASTElement {
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
// Set up global variables necessary to execute unit tests
|
||||
Object.entries(requiredTestObject).forEach(([key, value]) => {
|
||||
Object.defineProperty(globalThis, key, { value, configurable: true });
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
|
||||
// Tear down global variables set up during connectedCallback
|
||||
Object.keys(requiredTestObject).forEach(key => {
|
||||
delete globalThis[key];
|
||||
});
|
||||
}
|
||||
}).define(controllerElementName);
|
||||
|
||||
document.body.appendChild(document.createElement(controllerElementName));
|
|
@ -1,115 +0,0 @@
|
|||
import { css, FASTElement, html, Observable, Updates } from "@microsoft/fast-element";
|
||||
import { uniqueElementName } from "@microsoft/fast-element/testing.js";
|
||||
import type { Meta, Story } from "../../__test__/helpers.js";
|
||||
import { CSSDesignToken, DesignToken as FASTDesignToken } from "../fast-design-token.js";
|
||||
|
||||
export default {
|
||||
title: "Debug/DesignToken",
|
||||
} as Meta;
|
||||
|
||||
export const DesignToken: Story = () => {
|
||||
const controllerElementName = uniqueElementName();
|
||||
const fixtureElementName = uniqueElementName();
|
||||
|
||||
// Define element that can have token mutated for it
|
||||
(class extends FASTElement {}).define({
|
||||
name: fixtureElementName,
|
||||
template: html`
|
||||
<slot></slot>
|
||||
`,
|
||||
});
|
||||
|
||||
const elementCache = new Set<HTMLElement>();
|
||||
// The objects required for unit-testing
|
||||
// DesignToken. These get installed on the
|
||||
// globalThis during story connection, and
|
||||
// removed during disconnection
|
||||
const requiredTestObject = {
|
||||
DesignToken: FASTDesignToken,
|
||||
CSSDesignToken,
|
||||
uniqueTokenName() {
|
||||
return uniqueElementName() + "token";
|
||||
},
|
||||
createElement(): FASTElement {
|
||||
const element = document.createElement(fixtureElementName) as FASTElement;
|
||||
elementCache.add(element);
|
||||
return element;
|
||||
},
|
||||
addElement(parent = document.body) {
|
||||
const el = requiredTestObject.createElement();
|
||||
el.setAttribute("id", "id" + uniqueElementName());
|
||||
parent.appendChild(el);
|
||||
return el;
|
||||
},
|
||||
css,
|
||||
threw(fn: () => void): boolean {
|
||||
try {
|
||||
fn();
|
||||
return false;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
spy(fn: () => any) {
|
||||
let calls: number = 0;
|
||||
const callArgs: any = [];
|
||||
const f = (...args: any[]) => {
|
||||
calls += 1;
|
||||
callArgs[calls] = args;
|
||||
};
|
||||
Object.defineProperties(f, {
|
||||
calls: {
|
||||
get() {
|
||||
return calls;
|
||||
},
|
||||
},
|
||||
calledWith: {
|
||||
value: function (n: number): any {
|
||||
return callArgs[n];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return f;
|
||||
},
|
||||
Updates,
|
||||
Observable,
|
||||
cleanup() {
|
||||
elementCache.forEach(value => {
|
||||
value.parentElement?.removeChild(value);
|
||||
elementCache.delete(value);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
(class extends FASTElement {
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
// Set up global variables necessary to execute unit tests
|
||||
Object.entries(requiredTestObject).forEach(([key, value]) => {
|
||||
Object.defineProperty(globalThis, key, { value, configurable: true });
|
||||
});
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
|
||||
// Tear down global variables set up during connectedCallback
|
||||
Object.keys(requiredTestObject).forEach(key => {
|
||||
delete globalThis[key];
|
||||
});
|
||||
}
|
||||
}).define({
|
||||
name: controllerElementName,
|
||||
template: html`
|
||||
<h1>Nothing to see here, folks.</h1>
|
||||
<p>
|
||||
This page is an entrypoint for DesignToken unit tests and should only be
|
||||
used for programmatic purposes
|
||||
</p>
|
||||
`,
|
||||
});
|
||||
|
||||
return document.createElement(controllerElementName);
|
||||
};
|
|
@ -1,42 +1,54 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTDialog } from "./index.js";
|
||||
|
||||
test.describe("Dialog", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
let overlay: Locator;
|
||||
test("should include a role of `dialog` on the control", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
element = page.locator("fast-dialog");
|
||||
const control = element.locator(`[role="dialog"]`);
|
||||
|
||||
root = page.locator("#root");
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog></fast-dialog>
|
||||
`;
|
||||
});
|
||||
|
||||
control = element.locator(`[role="dialog"]`);
|
||||
|
||||
overlay = element.locator(".overlay");
|
||||
|
||||
await page.goto(fixtureURL("dialog--dialog"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of `dialog` on the control", async () => {
|
||||
await expect(control).toHaveClass(/control/);
|
||||
});
|
||||
|
||||
test('should set the `tabindex` attribute on the control to "-1" by default', async () => {
|
||||
test('should set the `tabindex` attribute on the control to "-1" by default', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const control = element.locator(`[role="dialog"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog></fast-dialog>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(control).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test("should set the `hidden` attribute to equal the value of the `hidden` property", async () => {
|
||||
test("should set the `hidden` attribute to equal the value of the `hidden` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog></fast-dialog>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTDialog) => {
|
||||
node.hidden = true;
|
||||
});
|
||||
|
@ -50,11 +62,19 @@ test.describe("Dialog", () => {
|
|||
await expect(element).not.toHaveBooleanAttribute("hidden");
|
||||
});
|
||||
|
||||
test("should set the `aria-describedby` attribute on the control when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-describedby` attribute on the control when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const control = element.locator(`[role="dialog"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog aria-describedby="description">
|
||||
<div id="description">Description</div>
|
||||
<div id="description">This is a description</div>
|
||||
</fast-dialog>
|
||||
`;
|
||||
});
|
||||
|
@ -62,8 +82,16 @@ test.describe("Dialog", () => {
|
|||
await expect(control).toHaveAttribute("aria-describedby", "description");
|
||||
});
|
||||
|
||||
test("should set the `aria-labelledby` attribute on the dialog control when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-labelledby` attribute on the dialog control when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const control = element.locator(`[role="dialog"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog aria-labelledby="label">
|
||||
<div id="label">Label</div>
|
||||
|
@ -74,8 +102,16 @@ test.describe("Dialog", () => {
|
|||
await expect(control).toHaveAttribute("aria-labelledby", "label");
|
||||
});
|
||||
|
||||
test("should set the `aria-label` attribute on the dialog control when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-label` attribute on the dialog control when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const control = element.locator(`[role="dialog"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog aria-label="Label"></fast-dialog>
|
||||
`;
|
||||
|
@ -84,8 +120,16 @@ test.describe("Dialog", () => {
|
|||
await expect(control).toHaveAttribute("aria-label", "Label");
|
||||
});
|
||||
|
||||
test("should add an attribute of `aria-modal` with a value equal to the `modal` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add an attribute of `aria-modal` with a value equal to the `modal` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const control = element.locator(`[role="dialog"]`);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
|
@ -100,8 +144,16 @@ test.describe("Dialog", () => {
|
|||
await expect(control).not.hasAttribute("aria-modal");
|
||||
});
|
||||
|
||||
test('should add an overlay element with a `role` attribute of "presentation" when the `modal` property is true', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should add an overlay element with a `role` attribute of "presentation" when the `modal` property is true', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const overlay = element.locator(".overlay");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
|
@ -116,8 +168,14 @@ test.describe("Dialog", () => {
|
|||
await expect(overlay).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should add an attribute of `no-focus-trap` when `noFocusTrap` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add an attribute of `no-focus-trap` when `noFocusTrap` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog no-focus-trap></fast-dialog>
|
||||
`;
|
||||
|
@ -136,7 +194,19 @@ test.describe("Dialog", () => {
|
|||
await expect(element).not.toHaveBooleanAttribute("no-focus-trap");
|
||||
});
|
||||
|
||||
test("should add the `hidden` attribute when the `hide()` method is invoked", async () => {
|
||||
test("should add the `hidden` attribute when the `hide()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTDialog) => {
|
||||
node.hidden = false;
|
||||
});
|
||||
|
@ -152,7 +222,19 @@ test.describe("Dialog", () => {
|
|||
await expect(element).toHaveJSProperty("hidden", true);
|
||||
});
|
||||
|
||||
test("should remove the `hidden` attribute when the `show()` method is invoked", async () => {
|
||||
test("should remove the `hidden` attribute when the `show()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTDialog) => {
|
||||
node.hidden = true;
|
||||
});
|
||||
|
@ -170,8 +252,16 @@ test.describe("Dialog", () => {
|
|||
await expect(element).not.toHaveBooleanAttribute("hidden");
|
||||
});
|
||||
|
||||
test("should fire a 'dismiss' event when its overlay is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a 'dismiss' event when its overlay is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const overlay = element.locator(".overlay");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
|
@ -193,8 +283,14 @@ test.describe("Dialog", () => {
|
|||
expect(wasDismissed).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should fire a `cancel` event when its overlay is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a `cancel` event when its overlay is clicked", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const overlay = element.locator(".overlay");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
|
@ -216,8 +312,16 @@ test.describe("Dialog", () => {
|
|||
expect(wasDismissed).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should fire a 'dismiss' event when keydown is invoked on the document", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a 'dismiss' event when keydown is invoked on the document", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-dialog");
|
||||
|
||||
const overlay = element.locator(".overlay");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-dialog modal></fast-dialog>
|
||||
`;
|
||||
|
|
|
@ -1,33 +1,45 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTDisclosure } from "./disclosure.js";
|
||||
|
||||
test.describe("Disclosure", () => {
|
||||
test.describe("States, Attributes, and Properties", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let summary: Locator;
|
||||
test("should set the `aria-controls` attribute on the internal summary element", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-disclosure");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const summary = element.locator("summary");
|
||||
|
||||
element = page.locator("fast-disclosure");
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
summary = element.locator("summary");
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-disclosure>
|
||||
<div slot="summary">Summary</div>
|
||||
<div slot="content">Content</div>
|
||||
</fast-disclosure>
|
||||
`;
|
||||
});
|
||||
|
||||
await page.goto(fixtureURL("disclosure--disclosure"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set the `aria-controls` attribute on the internal summary element", async () => {
|
||||
await expect(summary).toHaveAttribute("aria-controls", "disclosure-content");
|
||||
});
|
||||
|
||||
test("should toggle the `expanded` attribute based on the value of the `expanded` property", async () => {
|
||||
test("should toggle the `expanded` attribute based on the value of the `expanded` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-disclosure");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-disclosure>
|
||||
<div slot="summary">Summary</div>
|
||||
<div slot="content">Content</div>
|
||||
</fast-disclosure>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).not.toHaveBooleanAttribute("expanded");
|
||||
|
||||
await element.evaluate((node: FASTDisclosure) => {
|
||||
|
@ -43,7 +55,21 @@ test.describe("Disclosure", () => {
|
|||
await expect(element).not.toHaveBooleanAttribute("expanded");
|
||||
});
|
||||
|
||||
test("should set summary slot content to the value of the summary attribute", async () => {
|
||||
test("should set summary slot content to the value of the summary attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-disclosure");
|
||||
|
||||
const summary = element.locator("summary");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-disclosure></fast-disclosure>
|
||||
`;
|
||||
});
|
||||
|
||||
const summaryContent =
|
||||
"Should set the summary slot content to the value of the summary attribute";
|
||||
|
||||
|
@ -54,7 +80,22 @@ test.describe("Disclosure", () => {
|
|||
await expect(summary).toHaveText(summaryContent);
|
||||
});
|
||||
|
||||
test("should toggle the content when the `toggle()` method is invoked", async () => {
|
||||
test("should toggle the content when the `toggle()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-disclosure");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-disclosure>
|
||||
<div slot="summary">Summary</div>
|
||||
<div slot="content">Content</div>
|
||||
</fast-disclosure>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTDisclosure) => {
|
||||
node.toggle();
|
||||
});
|
||||
|
@ -68,7 +109,22 @@ test.describe("Disclosure", () => {
|
|||
await expect(element).toHaveJSProperty("expanded", false);
|
||||
});
|
||||
|
||||
test("should expand and collapse the content when the `show()` and `hide()` methods are invoked", async () => {
|
||||
test("should expand and collapse the content when the `show()` and `hide()` methods are invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-disclosure");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-disclosure>
|
||||
<div slot="summary">Summary</div>
|
||||
<div slot="content">Content</div>
|
||||
</fast-disclosure>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).toHaveJSProperty("expanded", false);
|
||||
|
||||
await element.evaluate((node: FASTDisclosure) => {
|
||||
|
@ -84,7 +140,24 @@ test.describe("Disclosure", () => {
|
|||
await expect(element).toHaveJSProperty("expanded", false);
|
||||
});
|
||||
|
||||
test("should set the `aria-expanded` attribute on the internal summary element equal to the `expanded` property", async () => {
|
||||
test("should set the `aria-expanded` attribute on the internal summary element equal to the `expanded` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-disclosure");
|
||||
|
||||
const summary = element.locator("summary");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-disclosure>
|
||||
<div slot="summary">Summary</div>
|
||||
<div slot="content">Content</div>
|
||||
</fast-disclosure>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(summary).toHaveAttribute("aria-expanded", "false");
|
||||
|
||||
await element.evaluate((node: FASTDisclosure) => {
|
||||
|
|
|
@ -1,30 +1,14 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import { DividerOrientation, DividerRole } from "./divider.options.js";
|
||||
import type { FASTDivider } from "./index.js";
|
||||
|
||||
test.describe("Divider", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test('should set a default `role` attribute of "separator"', async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const element = page.locator("fast-divider");
|
||||
|
||||
element = page.locator("fast-divider");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("divider--divider"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test('should set a default `role` attribute of "separator"', async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-divider></fast-divider>
|
||||
`;
|
||||
|
@ -33,8 +17,14 @@ test.describe("Divider", () => {
|
|||
await expect(element).toHaveAttribute("role", DividerRole.separator);
|
||||
});
|
||||
|
||||
test("should set the `role` attribute equal to the role provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `role` attribute equal to the role provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-divider");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-divider role="presentation"></fast-divider>
|
||||
`;
|
||||
|
@ -49,8 +39,14 @@ test.describe("Divider", () => {
|
|||
await expect(element).toHaveAttribute("role", DividerRole.separator);
|
||||
});
|
||||
|
||||
test("should set the `aria-orientation` attribute equal to the `orientation` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-orientation` attribute equal to the `orientation` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-divider");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-divider orientation="vertical"></fast-divider>
|
||||
`;
|
||||
|
@ -71,8 +67,14 @@ test.describe("Divider", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should NOT set the `aria-orientation` attribute equal to the `orientation` value if the `role` is presentational", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set the `aria-orientation` attribute equal to the `orientation` value if the `role` is presentational", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-divider");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-divider orientation="vertical"></fast-divider>
|
||||
`;
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTFlipper } from "./flipper.js";
|
||||
|
||||
test.describe("Flipper", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should include a role of button", async ({ page }) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-flipper");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("flipper--flipper"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of button", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper></fast-flipper>
|
||||
`;
|
||||
|
@ -32,8 +16,12 @@ test.describe("Flipper", () => {
|
|||
await expect(element).toHaveAttribute("role", "button");
|
||||
});
|
||||
|
||||
test('should set `aria-hidden` to "true" by default', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set `aria-hidden` to "true" by default', async ({ page }) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper></fast-flipper>
|
||||
`;
|
||||
|
@ -42,8 +30,14 @@ test.describe("Flipper", () => {
|
|||
await expect(element).toHaveAttribute("aria-hidden", "true");
|
||||
});
|
||||
|
||||
test("should set the `hiddenFromAT` property to true by default", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `hiddenFromAT` property to true by default", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper></fast-flipper>
|
||||
`;
|
||||
|
@ -52,8 +46,12 @@ test.describe("Flipper", () => {
|
|||
await expect(element).toHaveJSProperty("hiddenFromAT", true);
|
||||
});
|
||||
|
||||
test('should set the `direction` property to "next" by default', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the `direction` property to "next" by default', async ({ page }) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper></fast-flipper>
|
||||
`;
|
||||
|
@ -62,8 +60,14 @@ test.describe("Flipper", () => {
|
|||
await expect(element.locator("span")).toHaveClass(/next/);
|
||||
});
|
||||
|
||||
test("should toggle the `aria-disabled` attribute based on the value of the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should toggle the `aria-disabled` attribute based on the value of the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper disabled></fast-flipper>
|
||||
`;
|
||||
|
@ -80,8 +84,14 @@ test.describe("Flipper", () => {
|
|||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
});
|
||||
|
||||
test('should set the `tabindex` attribute to "-1" when `hiddenFromAT` is true', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the `tabindex` attribute to "-1" when `hiddenFromAT` is true', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper></fast-flipper>
|
||||
`;
|
||||
|
@ -104,8 +114,12 @@ test.describe("Flipper", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test("should set a `tabindex` of 0 when `aria-hidden` is false", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a `tabindex` of 0 when `aria-hidden` is false", async ({ page }) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper aria-hidden="false"></fast-flipper>
|
||||
`;
|
||||
|
@ -120,8 +134,14 @@ test.describe("Flipper", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test('should render a span with a class of "next" when the `direction` attribute is "next"', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should render a span with a class of "next" when the `direction` attribute is "next"', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper direction="next"></fast-flipper>
|
||||
`;
|
||||
|
@ -134,8 +154,14 @@ test.describe("Flipper", () => {
|
|||
await expect(spans).toHaveClass(/next/);
|
||||
});
|
||||
|
||||
test('should render a span with a class of "previous" when the `direction` attribute is "previous"', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should render a span with a class of "previous" when the `direction` attribute is "previous"', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-flipper");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-flipper direction="previous"></fast-flipper>
|
||||
`;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import type {
|
||||
|
@ -9,22 +7,12 @@ import type {
|
|||
} from "./stories/form-associated.register.js";
|
||||
|
||||
test.describe("FormAssociated", () => {
|
||||
let page: Page;
|
||||
let root: Locator;
|
||||
test("should have an empty string value prior to connectedCallback", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("debug--blank"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have an empty string value prior to connectedCallback", async () => {
|
||||
const [value, currentValue] = await root.evaluate(node => {
|
||||
const [value, currentValue] = await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const el = document.createElement("test-element") as FormAssociatedElement;
|
||||
|
@ -37,8 +25,12 @@ test.describe("FormAssociated", () => {
|
|||
expect(currentValue).toBe("");
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const el = document.createElement("test-element") as FormAssociatedElement;
|
||||
|
@ -57,8 +49,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("initialValue", "foobar");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value ATTRIBUTE if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value ATTRIBUTE if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const el = document.createElement("test-element") as FormAssociatedElement;
|
||||
|
@ -75,8 +71,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foobar");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value ATTRIBUTE if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value ATTRIBUTE if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<test-element></test-element>
|
||||
`;
|
||||
|
@ -93,8 +93,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foobar");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value PROPERTY if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value PROPERTY if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const el = document.createElement("test-element") as FormAssociatedElement;
|
||||
|
@ -111,8 +115,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foobar");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value PROPERTY if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value PROPERTY if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<test-element></test-element>
|
||||
`;
|
||||
|
@ -129,8 +137,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foobar");
|
||||
});
|
||||
|
||||
test("should initialize to the initial value when initial value is assigned by extending class", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value when initial value is assigned by extending class", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<custom-initial-value></custom-initial-value>
|
||||
`;
|
||||
|
@ -143,8 +155,10 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foobar");
|
||||
});
|
||||
|
||||
test("should communicate initial value to the parent form", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should communicate initial value to the parent form", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<custom-initial-value name="test"></custom-initial-value>
|
||||
|
@ -164,8 +178,12 @@ test.describe("FormAssociated", () => {
|
|||
});
|
||||
|
||||
test.describe("changes:", () => {
|
||||
test("setting value ATTRIBUTE should set value if value PROPERTY has not been explicitly set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("setting value ATTRIBUTE should set value if value PROPERTY has not been explicitly set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<test-element></test-element>
|
||||
`;
|
||||
|
@ -190,8 +208,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "bar");
|
||||
});
|
||||
|
||||
test("setting value ATTRIBUTE should not set value if value PROPERTY has been explicitly set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("setting value ATTRIBUTE should not set value if value PROPERTY has been explicitly set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<test-element></test-element>
|
||||
`;
|
||||
|
@ -216,8 +238,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foo");
|
||||
});
|
||||
|
||||
test("setting value ATTRIBUTE should set parent form value if value PROPERTY has not been explicitly set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("setting value ATTRIBUTE should set parent form value if value PROPERTY has not been explicitly set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<test-element name="test"></test-element>
|
||||
|
@ -254,8 +280,10 @@ test.describe("FormAssociated", () => {
|
|||
).toBe("bar");
|
||||
});
|
||||
|
||||
test("setting value PROPERTY should set parent form value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("setting value PROPERTY should set parent form value", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<test-element name="test"></test-element>
|
||||
|
@ -292,8 +320,12 @@ test.describe("FormAssociated", () => {
|
|||
).toBe("bar");
|
||||
});
|
||||
|
||||
test("assigning the currentValue property should set the controls value property to the same value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("assigning the currentValue property should set the controls value property to the same value", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<test-element></test-element>
|
||||
`;
|
||||
|
@ -314,8 +346,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveJSProperty("currentValue", "foo");
|
||||
});
|
||||
|
||||
test("setting the current-value property should set the controls value property to the same value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("setting the current-value property should set the controls value property to the same value", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<test-element></test-element>
|
||||
`;
|
||||
|
@ -338,8 +374,12 @@ test.describe("FormAssociated", () => {
|
|||
});
|
||||
|
||||
test.describe("when the owning form's reset() method is invoked", () => {
|
||||
test("should reset it's value property to an empty string if no value attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset it's value property to an empty string if no value attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<test-element name="test"></test-element>
|
||||
|
@ -372,8 +412,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).not.hasAttribute("value");
|
||||
});
|
||||
|
||||
test("should reset it's value property to the value of the value attribute if it is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset it's value property to the value of the value attribute if it is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<test-element name="test" value="attr-value"></test-element>
|
||||
|
@ -412,8 +456,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveAttribute("value", "attr-value");
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where modifcations to the `value` attribute update the `value` property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where modifcations to the `value` attribute update the `value` property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<test-element name="test" value="attr-value"></test-element>
|
||||
|
@ -464,8 +512,12 @@ test.describe("FormAssociated", () => {
|
|||
});
|
||||
|
||||
test.describe("CheckableFormAssociated", () => {
|
||||
test("should have a 'checked' property that is initialized to false", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a 'checked' property that is initialized to false", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<checkable-form-associated></checkable-form-associated>
|
||||
`;
|
||||
|
@ -480,8 +532,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveAttribute("current-checked", "false");
|
||||
});
|
||||
|
||||
test("should align the `currentChecked` property and `current-checked` attribute with `checked` property changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should align the `currentChecked` property and `current-checked` attribute with `checked` property changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<checkable-form-associated></checkable-form-associated>
|
||||
`;
|
||||
|
@ -516,8 +572,12 @@ test.describe("FormAssociated", () => {
|
|||
await expect(element).toHaveAttribute("current-checked", "false");
|
||||
});
|
||||
|
||||
test("should align the `checked` property and `current-checked` attribute with `currentChecked` property changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should align the `checked` property and `current-checked` attribute with `currentChecked` property changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<checkable-form-associated></checkable-form-associated>
|
||||
`;
|
||||
|
|
|
@ -1,60 +1,75 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTHorizontalScroll } from "./horizontal-scroll.js";
|
||||
|
||||
test.describe("HorizontalScroll", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
|
||||
let cards: Locator;
|
||||
let scrollNext: Locator;
|
||||
let scrollPrevious: Locator;
|
||||
let scrollView: Locator;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
|
||||
element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
cards = element.locator("fast-card");
|
||||
|
||||
scrollNext = element.locator(".scroll-next");
|
||||
|
||||
scrollPrevious = element.locator(".scroll-prev");
|
||||
|
||||
scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.goto(fixtureURL("horizontal-scroll--horizontal-scroll"));
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.speed = 0;
|
||||
});
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test.describe("Flippers", () => {
|
||||
test.beforeEach(async () => {
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.scrollToPosition(0);
|
||||
});
|
||||
});
|
||||
test("should enable the next flipper element when content exceeds horizontal-scroll width", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollNext = element.locator(".scroll-next");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll style="width: 1000px;">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
test("should enable the next flipper element when content exceeds horizontal-scroll width", async () => {
|
||||
await expect(scrollNext).not.toHaveClass(/disabled/);
|
||||
});
|
||||
|
||||
test("should start in the 0 position", async () => {
|
||||
test("should start in the 0 position", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(scrollView).toHaveJSProperty("scrollLeft", 0);
|
||||
});
|
||||
|
||||
test("should scroll to the beginning of the last element in full view", async () => {
|
||||
test("should scroll to the beginning of the last element in full view", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const cards = element.locator("fast-card");
|
||||
|
||||
const scrollNext = element.locator(".scroll-next");
|
||||
|
||||
const scrollPrevious = element.locator(".scroll-prev");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.scrollToNext();
|
||||
});
|
||||
|
@ -62,7 +77,23 @@ test.describe("HorizontalScroll", () => {
|
|||
await expect(scrollView).toHaveJSProperty("scrollLeft", 375);
|
||||
});
|
||||
|
||||
test("should not scroll past the beginning", async () => {
|
||||
test("should not scroll past the beginning", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(scrollView).toHaveJSProperty("scrollLeft", 0);
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
|
@ -72,7 +103,27 @@ test.describe("HorizontalScroll", () => {
|
|||
await expect(scrollView).toHaveJSProperty("scrollLeft", 0);
|
||||
});
|
||||
|
||||
test("should not scroll past the last in view element", async () => {
|
||||
test("should not scroll past the last in view element", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const cards = element.locator("fast-card");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await (await element.elementHandle())?.waitForElementState("stable");
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
const scrollView = node.shadowRoot?.querySelector(".scroll-view");
|
||||
|
||||
|
@ -98,7 +149,31 @@ test.describe("HorizontalScroll", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test('should set the "disabled" class on the previous flipper when the scroll position is at the beginning of the content', async () => {
|
||||
test('should set the "disabled" class on the previous flipper when the scroll position is at the beginning of the content', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const cards = element.locator("fast-card");
|
||||
|
||||
const scrollNext = element.locator(".scroll-next");
|
||||
|
||||
const scrollPrevious = element.locator(".scroll-prev");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(scrollPrevious).toHaveClass(/disabled/);
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
|
@ -114,7 +189,31 @@ test.describe("HorizontalScroll", () => {
|
|||
await expect(scrollPrevious).toHaveClass(/disabled/);
|
||||
});
|
||||
|
||||
test('should set the "disabled" class on the next flipper when the scroll position is at the end of the content', async () => {
|
||||
test('should set the "disabled" class on the next flipper when the scroll position is at the end of the content', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const cards = element.locator("fast-card");
|
||||
|
||||
const scrollNext = element.locator(".scroll-next");
|
||||
|
||||
const scrollPrevious = element.locator(".scroll-prev");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(scrollNext).not.toHaveClass(/disabled/);
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
|
@ -129,46 +228,60 @@ test.describe("HorizontalScroll", () => {
|
|||
|
||||
await expect(scrollNext).not.toHaveClass(/disabled/);
|
||||
});
|
||||
});
|
||||
|
||||
test("should hide the next flipper if content is less than horizontal-scroll width", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll style="width: 1000px;">
|
||||
<fast-card style="width: 100px;"></fast-card>
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
test("should hide the next flipper if content is less than horizontal-scroll width", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollNext = element.locator(".scroll-next");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll style="width: 1000px;">
|
||||
<fast-card style="width: 100px;"></fast-card>
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(scrollNext).toBeHidden();
|
||||
});
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollNext = element.locator(".scroll-next");
|
||||
|
||||
await expect(scrollNext).toBeHidden();
|
||||
});
|
||||
|
||||
test.describe("Scrolling", () => {
|
||||
test("should change scroll stop on resize", async () => {
|
||||
await page.goto(
|
||||
fixtureURL("horizontal-scroll--horizontal-scroll", { speed: 0 })
|
||||
);
|
||||
test("should change scroll stop on resize", async ({ page }) => {
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
const flippers = element.locator("fast-flipper");
|
||||
|
||||
const previousFlipper = flippers.nth(0);
|
||||
|
||||
const nextFlipper = flippers.nth(1);
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await nextFlipper.click();
|
||||
|
||||
await expect(scrollView).toHaveJSProperty("scrollLeft", 375);
|
||||
|
||||
await previousFlipper.click();
|
||||
|
||||
await expect(scrollView).toHaveJSProperty("scrollLeft", 0);
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.style.setProperty("max-width", "400px");
|
||||
});
|
||||
|
@ -181,14 +294,22 @@ test.describe("HorizontalScroll", () => {
|
|||
test("should scroll to previous when only 2 items wide", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 250, height: 250 });
|
||||
|
||||
await page.goto(
|
||||
fixtureURL("horizontal-scroll--horizontal-scroll", { speed: 0 })
|
||||
);
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.scrollToNext();
|
||||
});
|
||||
|
@ -205,18 +326,26 @@ test.describe("HorizontalScroll", () => {
|
|||
test("should scroll item into view when the `scrollInView()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(
|
||||
fixtureURL("horizontal-scroll--horizontal-scroll", { speed: 0 })
|
||||
);
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
cards = element.locator("fast-card");
|
||||
const cards = element.locator("fast-card");
|
||||
|
||||
const lastCard = cards.last();
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll, card) => {
|
||||
node.scrollInView(card as HTMLElement, 0);
|
||||
}, await lastCard.elementHandle());
|
||||
|
@ -233,9 +362,7 @@ test.describe("HorizontalScroll", () => {
|
|||
test("Should scroll item into view with `scrollInView()` by index", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(
|
||||
fixtureURL("horizontal-scroll--horizontal-scroll", { speed: 0 })
|
||||
);
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
|
@ -245,6 +372,16 @@ test.describe("HorizontalScroll", () => {
|
|||
|
||||
const lastCard = cards.last();
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll, cardsCount) => {
|
||||
node.scrollInView(cardsCount - 1, 0);
|
||||
}, await cards.count());
|
||||
|
@ -261,9 +398,7 @@ test.describe("HorizontalScroll", () => {
|
|||
test("Should scroll item into view respecting right and left padding", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(
|
||||
fixtureURL("horizontal-scroll--horizontal-scroll", { speed: 0 })
|
||||
);
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
|
@ -273,6 +408,16 @@ test.describe("HorizontalScroll", () => {
|
|||
|
||||
const thirdLastCard = cards.nth(-4);
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.scrollInView(12, 0);
|
||||
});
|
||||
|
@ -307,14 +452,22 @@ test.describe("HorizontalScroll", () => {
|
|||
test("Should not scroll with `scrollInView()` when the item is in view", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(
|
||||
fixtureURL("horizontal-scroll--horizontal-scroll", { speed: 0 })
|
||||
);
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const element = page.locator("fast-horizontal-scroll");
|
||||
|
||||
const scrollView = element.locator(".scroll-view");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-horizontal-scroll speed="0">
|
||||
${[...Array(16)]
|
||||
.map((_, i) => /* html */ `<fast-card>card ${i + 1}</fast-card>`)
|
||||
.join("")}
|
||||
</fast-horizontal-scroll>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTHorizontalScroll) => {
|
||||
node.scrollInView(2);
|
||||
});
|
||||
|
|
|
@ -70,6 +70,14 @@ const styles = css`
|
|||
contain: layout;
|
||||
display: block;
|
||||
position: relative;
|
||||
max-width: 620px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
::slotted(fast-card) {
|
||||
color: var(--neutral-foreground-rest);
|
||||
height: 200px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTListboxOption } from "./listbox-option.js";
|
||||
|
||||
test.describe("ListboxOption", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should have a role of `option`", async ({ page }) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-option");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("listbox-option--listbox-option"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `option`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option></fast-option>
|
||||
`;
|
||||
|
@ -32,8 +16,12 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveAttribute("role", "option");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute when disabled", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute when disabled", async ({ page }) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option disabled></fast-option>
|
||||
`;
|
||||
|
@ -48,8 +36,12 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-selected` attribute when selected", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-selected` attribute when selected", async ({ page }) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option selected></fast-option>
|
||||
`;
|
||||
|
@ -64,8 +56,12 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveAttribute("aria-selected", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-checked` attribute when checked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-checked` attribute when checked", async ({ page }) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option></fast-option>
|
||||
`;
|
||||
|
@ -86,8 +82,14 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should have an empty string `value` when the `value` attribute exists and is empty", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have an empty string `value` when the `value` attribute exists and is empty", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option value=""></fast-option>
|
||||
`;
|
||||
|
@ -102,8 +104,14 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveAttribute("value", "");
|
||||
});
|
||||
|
||||
test("should return the text content when the `value` attribute does not exist", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the text content when the `value` attribute does not exist", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option>hello</fast-option>
|
||||
`;
|
||||
|
@ -114,8 +122,14 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveJSProperty("value", "hello");
|
||||
});
|
||||
|
||||
test("should return the trimmed text content with the `text` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the trimmed text content with the `text` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option>
|
||||
hello
|
||||
|
@ -129,8 +143,12 @@ test.describe("ListboxOption", () => {
|
|||
await expect(element).toHaveText("hello world");
|
||||
});
|
||||
|
||||
test("should always return the `value` as a string", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should always return the `value` as a string", async ({ page }) => {
|
||||
const element = page.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-option value="1"></fast-option>
|
||||
`;
|
||||
|
|
|
@ -1,32 +1,15 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTListboxElement } from "./listbox.element.js";
|
||||
|
||||
test.describe("Listbox", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let options: Locator;
|
||||
test("should have a tabindex of 0 when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-listbox");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
options = element.locator("fast-option");
|
||||
|
||||
await page.goto(fixtureURL("listbox--listbox"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a tabindex of 0 when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -39,8 +22,12 @@ test.describe("Listbox", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should NOT have a tabindex when `disabled` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT have a tabindex when `disabled` is true", async ({ page }) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox disabled></fast-listbox>
|
||||
`;
|
||||
|
@ -49,8 +36,16 @@ test.describe("Listbox", () => {
|
|||
await expect(element).not.hasAttribute("tabindex");
|
||||
});
|
||||
|
||||
test("should select nothing when no options have the `selected` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should select nothing when no options have the `selected` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
const options = element.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -71,8 +66,14 @@ test.describe("Listbox", () => {
|
|||
await expect(element).toHaveJSProperty("selectedIndex", -1);
|
||||
});
|
||||
|
||||
test("should select the option with a `selected` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should select the option with a `selected` attribute", async ({ page }) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
const options = element.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -89,8 +90,14 @@ test.describe("Listbox", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test("should set the `size` property to match the `size` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `size` property to match the `size` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox size="5"></fast-listbox>
|
||||
`;
|
||||
|
@ -99,8 +106,14 @@ test.describe("Listbox", () => {
|
|||
await expect(element).toHaveJSProperty("size", 5);
|
||||
});
|
||||
|
||||
test("should set the `size` attribute to match the `size` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `size` attribute to match the `size` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -117,65 +130,78 @@ test.describe("Listbox", () => {
|
|||
await expect(element).toHaveAttribute("size", "5");
|
||||
});
|
||||
|
||||
test.describe(
|
||||
"should set the `size` property to 0 when a negative value is set",
|
||||
() => {
|
||||
test("via the `size` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
test.describe("should set the `size` property to 0 when a negative value is set", () => {
|
||||
test("via the `size` property", async ({ page }) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-listbox>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTListboxElement) => {
|
||||
node.size = 1;
|
||||
});
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 1);
|
||||
await expect(element).toHaveAttribute("size", "1");
|
||||
|
||||
await element.evaluate((node: FASTListboxElement) => {
|
||||
node.size = -1;
|
||||
});
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 0);
|
||||
await expect(element).toHaveAttribute("size", "0");
|
||||
});
|
||||
|
||||
test("via the `size` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
await element.evaluate((node: FASTListboxElement) => {
|
||||
node.size = 1;
|
||||
});
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 1);
|
||||
await expect(element).toHaveAttribute("size", "1");
|
||||
|
||||
await element.evaluate((node: FASTListboxElement) => {
|
||||
node.size = -1;
|
||||
});
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 0);
|
||||
await expect(element).toHaveAttribute("size", "0");
|
||||
});
|
||||
|
||||
test("via the `size` attribute", async ({ page }) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-listbox>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate((node: FASTListboxElement) =>
|
||||
node.setAttribute("size", "1")
|
||||
);
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 1);
|
||||
await expect(element).toHaveAttribute("size", "1");
|
||||
|
||||
await element.evaluate((node: FASTListboxElement) =>
|
||||
node.setAttribute("size", "-1")
|
||||
);
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 0);
|
||||
await expect(element).toHaveAttribute("size", "0");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
test("should set the `aria-setsize` and `aria-posinset` properties on slotted options", async () => {
|
||||
await root.evaluate(node => {
|
||||
await element.evaluate((node: FASTListboxElement) =>
|
||||
node.setAttribute("size", "1")
|
||||
);
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 1);
|
||||
await expect(element).toHaveAttribute("size", "1");
|
||||
|
||||
await element.evaluate((node: FASTListboxElement) =>
|
||||
node.setAttribute("size", "-1")
|
||||
);
|
||||
|
||||
await expect(element).toHaveJSProperty("size", 0);
|
||||
await expect(element).toHaveAttribute("size", "0");
|
||||
});
|
||||
});
|
||||
|
||||
test("should set the `aria-setsize` and `aria-posinset` properties on slotted options", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
const options = element.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -197,8 +223,16 @@ test.describe("Listbox", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set a unique ID for each slotted option without an ID", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a unique ID for each slotted option without an ID", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
const options = element.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -215,8 +249,16 @@ test.describe("Listbox", () => {
|
|||
await expect(options.nth(2)).toHaveAttribute("id", /option-\d+/);
|
||||
});
|
||||
|
||||
test("should set the `aria-activedescendant` property to the ID of the currently selected option", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-activedescendant` property to the ID of the currently selected option", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
const options = element.locator("fast-option");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -239,8 +281,14 @@ test.describe("Listbox", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set the `aria-multiselectable` attribute to match the `multiple` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-multiselectable` attribute to match the `multiple` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-listbox");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-listbox>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
export { FASTMenuItem, MenuItemRole, roleForMenuItem } from "./menu-item.js";
|
||||
export type { MenuItemOptions } from "./menu-item.js";
|
||||
export { menuItemTemplate } from "./menu-item.template.js";
|
||||
export {
|
||||
FASTMenuItem,
|
||||
MenuItemOptions,
|
||||
MenuItemRole,
|
||||
roleForMenuItem,
|
||||
} from "./menu-item.js";
|
||||
|
|
|
@ -1,30 +1,16 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTMenuItem } from "./menu-item.js";
|
||||
import { MenuItemRole } from "./menu-item.options.js";
|
||||
|
||||
test.describe("Menu item", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should include a role of `menuitem` by default when no role is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-menu-item");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("menu-item--menu-item"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of `menuitem` by default when no role is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -33,30 +19,37 @@ test.describe("Menu item", () => {
|
|||
await expect(element).toHaveAttribute("role", MenuItemRole.menuitem);
|
||||
});
|
||||
|
||||
test.describe(
|
||||
"should include a matching role when the `role` property is provided",
|
||||
() => {
|
||||
let role: MenuItemRole;
|
||||
for (role in MenuItemRole) {
|
||||
test(role, async () => {
|
||||
await root.evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
test.describe("should include a matching role when the `role` property is provided", () => {
|
||||
let role: MenuItemRole;
|
||||
for (role in MenuItemRole) {
|
||||
test(role, async ({ page }) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await element.evaluate(
|
||||
(node: FASTMenuItem, role) => (node.role = role),
|
||||
role
|
||||
);
|
||||
await expect(element).toHaveAttribute("role", role);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
test("should set the `aria-disabled` attribute with the `disabled` value when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
await element.evaluate((node: FASTMenuItem, role) => {
|
||||
node.role = role;
|
||||
}, role);
|
||||
|
||||
await expect(element).toHaveAttribute("role", role);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute with the `disabled` value when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item disabled>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -65,8 +58,14 @@ test.describe("Menu item", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "true");
|
||||
});
|
||||
|
||||
test("should set an `aria-expanded` attribute with the `expanded` value when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set an `aria-expanded` attribute with the `expanded` value when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item expanded>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -75,8 +74,14 @@ test.describe("Menu item", () => {
|
|||
await expect(element).toHaveAttribute("aria-expanded", "true");
|
||||
});
|
||||
|
||||
test("should set an `aria-checked` attribute with the `checked` value when provided to a menuitemcheckbox", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set an `aria-checked` attribute with the `checked` value when provided to a menuitemcheckbox", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item role="menuitemcheckbox" checked>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -85,8 +90,14 @@ test.describe("Menu item", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "true");
|
||||
});
|
||||
|
||||
test("should NOT set an `aria-checked` attribute when checked is provided to a menuitem", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set an `aria-checked` attribute when checked is provided to a menuitem", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item role="menuitem" checked>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -95,14 +106,20 @@ test.describe("Menu item", () => {
|
|||
await expect(element).not.toHaveAttribute("aria-checked", "true");
|
||||
});
|
||||
|
||||
test("should toggle the `aria-checked` attribute of checkbox item when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should toggle the `aria-checked` attribute of checkbox item when clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item role="menuitemcheckbox">Menu item</fast-menu-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).hasAttribute("aria-checked", "false");
|
||||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
|
||||
await element.click();
|
||||
|
||||
|
@ -113,14 +130,20 @@ test.describe("Menu item", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-checked` attribute of radio item to true when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-checked` attribute of radio item when clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item role="menuitemradio">Menu item</fast-menu-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).hasAttribute("aria-checked", "false");
|
||||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
|
||||
await element.click();
|
||||
|
||||
|
@ -132,8 +155,12 @@ test.describe("Menu item", () => {
|
|||
});
|
||||
|
||||
test.describe("events", () => {
|
||||
test("should emit a `change` an event when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should emit a `change` event when clicked", async ({ page }) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -149,11 +176,17 @@ test.describe("Menu item", () => {
|
|||
element.click(),
|
||||
]);
|
||||
|
||||
expect(wasClicked).toBe(true);
|
||||
expect.soft(wasClicked).toBe(true);
|
||||
});
|
||||
|
||||
test("should emit a `keydown` event when space key is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should emit a `keydown` event when space key is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -165,20 +198,30 @@ test.describe("Menu item", () => {
|
|||
new Promise(resolve => {
|
||||
node.addEventListener("keydown", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve => setTimeout(() => resolve(false), 100)),
|
||||
new Promise(resolve =>
|
||||
requestAnimationFrame(() =>
|
||||
setTimeout(() => resolve(false), 100)
|
||||
)
|
||||
),
|
||||
])
|
||||
),
|
||||
// FIXME: Playwright's keyboard API is not working as expected.
|
||||
element.evaluate(node =>
|
||||
node.dispatchEvent(new KeyboardEvent("keydown", { key: " " }))
|
||||
),
|
||||
element.evaluate(node => {
|
||||
node.dispatchEvent(new KeyboardEvent("keydown", { key: " " }));
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBe(true);
|
||||
expect.soft(wasChanged).toBe(true);
|
||||
});
|
||||
|
||||
test("should emit a `keydown` event when `Enter` key is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should emit a `keydown` event when `Enter` key is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
`;
|
||||
|
@ -190,16 +233,20 @@ test.describe("Menu item", () => {
|
|||
new Promise(resolve => {
|
||||
node.addEventListener("keydown", () => resolve(true));
|
||||
}),
|
||||
new Promise(resolve => setTimeout(() => resolve(false), 100)),
|
||||
new Promise(resolve =>
|
||||
requestAnimationFrame(() =>
|
||||
setTimeout(() => resolve(false), 100)
|
||||
)
|
||||
),
|
||||
])
|
||||
),
|
||||
// FIXME: Playwright's keyboard API is not working as expected.
|
||||
element.evaluate(node =>
|
||||
node.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" }))
|
||||
),
|
||||
element.evaluate(node => {
|
||||
node.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter" }));
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(wasChanged).toBe(true);
|
||||
expect.soft(wasChanged).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Placement } from "@floating-ui/dom";
|
||||
import type { ElementRects, Placement } from "@floating-ui/dom";
|
||||
import { autoUpdate, computePosition, flip, shift, size } from "@floating-ui/dom";
|
||||
import { attr, FASTElement, observable, Updates } from "@microsoft/fast-element";
|
||||
import {
|
||||
|
@ -8,10 +8,10 @@ import {
|
|||
keyEscape,
|
||||
keySpace,
|
||||
} from "@microsoft/fast-web-utilities";
|
||||
import type { StaticallyComposableHTML } from "../utilities/template-helpers.js";
|
||||
import type { StartEndOptions } from "../patterns/start-end.js";
|
||||
import { StartEnd } from "../patterns/start-end.js";
|
||||
import { applyMixins } from "../utilities/apply-mixins.js";
|
||||
import type { StaticallyComposableHTML } from "../utilities/template-helpers.js";
|
||||
import { MenuItemRole, roleForMenuItem } from "./menu-item.options.js";
|
||||
|
||||
export { MenuItemRole, roleForMenuItem };
|
||||
|
@ -337,7 +337,13 @@ export class FASTMenuItem extends FASTElement {
|
|||
middleware: [
|
||||
shift(),
|
||||
size({
|
||||
apply: ({ availableWidth, rects }) => {
|
||||
apply: ({
|
||||
availableWidth,
|
||||
rects,
|
||||
}: {
|
||||
availableWidth: number;
|
||||
rects: ElementRects;
|
||||
}) => {
|
||||
if (availableWidth < rects.floating.width) {
|
||||
fallbackPlacements.push("bottom-end", "top-end");
|
||||
}
|
||||
|
|
|
@ -1,32 +1,12 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTMenu } from "./menu.js";
|
||||
|
||||
test.describe("Menu", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let menuItems: Locator;
|
||||
test("should have a role of `menu`", async ({ page }) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-menu");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto(fixtureURL("menu--menu"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `menu`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
|
@ -37,8 +17,16 @@ test.describe("Menu", () => {
|
|||
await expect(element).toHaveAttribute("role", "menu");
|
||||
});
|
||||
|
||||
test("should set `tabindex` of the first focusable menu item to 0", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `tabindex` of the first focusable menu item to 0", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
|
@ -50,8 +38,12 @@ test.describe("Menu", () => {
|
|||
await expect(menuItems.first()).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should NOT set any `tabindex` on non-menu-item elements", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set any `tabindex` on non-menu-item elements", async ({ page }) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
|
@ -65,8 +57,14 @@ test.describe("Menu", () => {
|
|||
expect(await divider.getAttribute("tabindex")).toBeNull();
|
||||
});
|
||||
|
||||
test("should focus on first menu item when focus is called", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should focus on first menu item when focus is called", async ({ page }) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item</fast-menu-item>
|
||||
|
@ -75,37 +73,43 @@ test.describe("Menu", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
await element.waitFor({ state: "attached" });
|
||||
|
||||
await expect(menuItems.first()).toHaveAttribute("tabindex", "0");
|
||||
|
||||
await root.evaluate(node => {
|
||||
document.querySelector<FASTMenu>("fast-menu")?.focus();
|
||||
await element.evaluate(node => {
|
||||
node.focus();
|
||||
});
|
||||
|
||||
expect(
|
||||
await menuItems.first().evaluate(node => {
|
||||
return node.isSameNode(document.activeElement);
|
||||
})
|
||||
).toBeTruthy();
|
||||
await expect(menuItems.first()).toBeFocused();
|
||||
});
|
||||
|
||||
test("should not throw when focus is called with no items", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not throw when focus is called with no items", async ({ page }) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu></fast-menu>
|
||||
`;
|
||||
});
|
||||
|
||||
await root.evaluate(node => {
|
||||
document.querySelector<FASTMenu>("fast-menu")?.focus();
|
||||
await element.evaluate(node => {
|
||||
node.focus();
|
||||
});
|
||||
|
||||
expect(await page.evaluate(() => document.activeElement?.id)).toBe("");
|
||||
await expect(element).not.toBeFocused();
|
||||
|
||||
// expect(await page.evaluate(() => document.activeElement?.id)).toBe("");
|
||||
});
|
||||
|
||||
test("should not throw when focus is called before initialization is complete", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not throw when focus is called before initialization is complete", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const menu = document.createElement("fast-menu");
|
||||
|
@ -115,11 +119,19 @@ test.describe("Menu", () => {
|
|||
node.append(menu);
|
||||
});
|
||||
|
||||
expect(await page.evaluate(() => document.activeElement?.id)).toBe("");
|
||||
await expect(element).not.toBeFocused();
|
||||
});
|
||||
|
||||
test("should focus disabled items", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should focus disabled items", async ({ page }) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
const firstMenuItem = menuItems.first();
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item disabled>Menu item</fast-menu-item>
|
||||
|
@ -128,8 +140,6 @@ test.describe("Menu", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
const firstMenuItem = menuItems.first();
|
||||
|
||||
await expect(firstMenuItem).toBeDisabled();
|
||||
|
||||
await expect(firstMenuItem).toHaveAttribute("tabindex", "0");
|
||||
|
@ -140,26 +150,40 @@ test.describe("Menu", () => {
|
|||
});
|
||||
|
||||
["menuitem", "menuitemcheckbox", "menuitemradio"].forEach(role => {
|
||||
test(`should accept elements as focusable child with "${role}" role`, async () => {
|
||||
await root.evaluate(
|
||||
test(`should accept elements as focusable child with "${role}" role`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const compatibleElement = element.locator(`[role="${role}"]`);
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { role }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<div role="${role}">Menu item</div>
|
||||
</fast-menu>
|
||||
`;
|
||||
<fast-menu>
|
||||
<div role="${role}">Menu item</div>
|
||||
</fast-menu>
|
||||
`;
|
||||
},
|
||||
{ role }
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.locator(`fast-menu [role="${role}"]`).first()
|
||||
).toHaveAttribute("tabindex", "0");
|
||||
await expect(compatibleElement).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
});
|
||||
|
||||
test("should not navigate to hidden items when changed after connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not navigate to hidden items when changed after connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item 1</fast-menu-item>
|
||||
|
@ -217,8 +241,16 @@ test.describe("Menu", () => {
|
|||
await expect(menuItems.nth(2)).toBeFocused();
|
||||
});
|
||||
|
||||
test("should treat all checkbox menu items as individually selectable items", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should treat all checkbox menu items as individually selectable items", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item role="menuitemcheckbox">Menu item 1</fast-menu-item>
|
||||
|
@ -246,8 +278,16 @@ test.describe("Menu", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test(`should treat all radio menu items as a radiogroup and limit selection to one item within the group`, async () => {
|
||||
await root.evaluate(node => {
|
||||
test(`should treat all radio menu items as a radiogroup and limit selection to one item within the group`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item role="menuitemradio">Menu item 1</fast-menu-item>
|
||||
|
@ -282,8 +322,16 @@ test.describe("Menu", () => {
|
|||
await expect(menuItems.nth(2)).toHaveAttribute("aria-checked", "true");
|
||||
});
|
||||
|
||||
test('should use elements with `[role="separator"]` to divide radio menu items into different radio groups', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should use elements with `[role="separator"]` to divide radio menu items into different radio groups', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item role="menuitemradio">Menu item 1</fast-menu-item>
|
||||
|
@ -324,8 +372,14 @@ test.describe("Menu", () => {
|
|||
await expect(menuItems.nth(3)).toHaveAttribute("aria-checked", "true");
|
||||
});
|
||||
|
||||
test("should navigate the menu on arrow up/down keys", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should navigate the menu on arrow up/down keys", async ({ page }) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item 1</fast-menu-item>
|
||||
|
@ -359,9 +413,15 @@ test.describe("Menu", () => {
|
|||
await expect(menuItems.nth(3)).toBeFocused();
|
||||
});
|
||||
|
||||
test("should close the menu when pressing the escape key", async () => {
|
||||
test("should close the menu when pressing the escape key", async ({ page }) => {
|
||||
test.slow();
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item 1
|
||||
|
@ -392,8 +452,16 @@ test.describe("Menu", () => {
|
|||
await expect(menuItems.first()).toBeFocused();
|
||||
});
|
||||
|
||||
test("should not navigate to hidden items when set before connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not navigate to hidden items when set before connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-menu");
|
||||
|
||||
const menuItems = element.locator("fast-menu-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-menu>
|
||||
<fast-menu-item>Menu item 1</fast-menu-item>
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { html } from "@microsoft/fast-element";
|
||||
import { attr } from "@microsoft/fast-element";
|
||||
import { css } from "@microsoft/fast-element";
|
||||
import { attr, css, html } from "@microsoft/fast-element";
|
||||
import { FASTMenuItem, MenuItemRole, menuItemTemplate } from "../../menu-item/index.js";
|
||||
import { FASTMenu } from "../menu.js";
|
||||
import { menuTemplate } from "../menu.template.js";
|
||||
|
@ -57,8 +55,8 @@ export class FancyMenu extends FASTMenu {
|
|||
|
||||
this.menuItems
|
||||
?.filter(this.isMenuItemElement)
|
||||
.forEach((item: HTMLElement, index: number) => {
|
||||
const indent: FancyMenuItemColumnCount = this.menuItems!.reduce(
|
||||
.forEach((item: HTMLElement, index: number, menuItems) => {
|
||||
const indent: FancyMenuItemColumnCount = menuItems.reduce(
|
||||
(accum, current) => {
|
||||
const elementValue = FancyMenu.elementIndent(
|
||||
current as HTMLElement
|
||||
|
|
|
@ -5,10 +5,7 @@ import { storyTemplate as menuItemStoryTemplate } from "../../menu-item/stories/
|
|||
import type { Meta, Story, StoryArgs } from "../../__test__/helpers.js";
|
||||
import { renderComponent } from "../../__test__/helpers.js";
|
||||
import type { FASTMenu } from "../menu.js";
|
||||
import type {
|
||||
FancyMenu as MyFancyMenu,
|
||||
FancyMenuItem as MyFancyMenuItem,
|
||||
} from "./menu.register.js";
|
||||
import type { FancyMenu as MyFancyMenu } from "./menu.register.js";
|
||||
|
||||
const storyTemplate = html<StoryArgs<FASTMenu>>`
|
||||
<fast-menu slot="${x => x.slot}">${x => x.storyContent}</fast-menu>
|
||||
|
@ -39,15 +36,6 @@ const fancyMenuItemStoryTemplate = html<StoryArgs<FASTMenuItem>>`
|
|||
</fancy-menu-item>
|
||||
`;
|
||||
|
||||
const fancyStoryContentTemplate = html`
|
||||
${repeat(
|
||||
x => x.storyItems,
|
||||
html<StoryArgs<MyFancyMenuItem>>`
|
||||
${x => x.template ?? fancyMenuItemStoryTemplate}
|
||||
`
|
||||
)}
|
||||
`;
|
||||
|
||||
export default {
|
||||
title: "Menu",
|
||||
args: {
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTNumberField } from "./number-field.js";
|
||||
|
||||
test.describe("NumberField", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
test("should initialize to the provided value attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-number-field");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(".control");
|
||||
|
||||
await page.goto(fixtureURL("number-field--number-field"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field value="10"></fast-number-field>
|
||||
`;
|
||||
|
@ -36,8 +19,16 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "10");
|
||||
});
|
||||
|
||||
test("should set the `autofocus` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `autofocus` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field autofocus></fast-number-field>
|
||||
`;
|
||||
|
@ -46,8 +37,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("autofocus");
|
||||
});
|
||||
|
||||
test("should set the `disabled` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `disabled` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field disabled></fast-number-field>
|
||||
`;
|
||||
|
@ -55,8 +54,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("disabled");
|
||||
});
|
||||
|
||||
test("should set the `readonly` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `readonly` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field readonly></fast-number-field>
|
||||
`;
|
||||
|
@ -64,8 +71,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("readonly");
|
||||
});
|
||||
|
||||
test("should set the `required` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `required` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field required></fast-number-field>
|
||||
`;
|
||||
|
@ -103,8 +118,16 @@ test.describe("NumberField", () => {
|
|||
})) {
|
||||
const attrToken = spinalCase(attribute);
|
||||
|
||||
test(`should set the \`${attrToken}\` attribute to "${value}" on the internal control`, async () => {
|
||||
await root.evaluate(
|
||||
test(`should set the \`${attrToken}\` attribute to "${value}" on the internal control`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { attrToken, value }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field ${attrToken}="${value}"></fast-number-field>
|
||||
|
@ -117,8 +140,16 @@ test.describe("NumberField", () => {
|
|||
});
|
||||
}
|
||||
|
||||
test("should set `value` property equal to the `max` property when value is greater than max", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `value` property equal to the `max` property when value is greater than max", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field max="10"></fast-number-field>
|
||||
`;
|
||||
|
@ -129,8 +160,14 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "10");
|
||||
});
|
||||
|
||||
test("should set `value` property equal to the `max` property when max is less than the value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `value` property equal to the `max` property when max is less than the value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field value="20"></fast-number-field>
|
||||
`;
|
||||
|
@ -145,8 +182,16 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "10");
|
||||
});
|
||||
|
||||
test("should set the `value` property equal to the `min` property when value is less than min", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `value` property equal to the `min` property when value is less than min", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="10"></fast-number-field>
|
||||
`;
|
||||
|
@ -159,8 +204,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("10");
|
||||
});
|
||||
|
||||
test("should update the `value` property when the `min` property is greater than the `value`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the `value` property when the `min` property is greater than the `value`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field value="10"></fast-number-field>
|
||||
`;
|
||||
|
@ -175,8 +228,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("20");
|
||||
});
|
||||
|
||||
test("should set the `max` property equal to the `min` property when min is greater than max", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `max` property equal to the `min` property when min is greater than max", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="10" max="5"></fast-number-field>
|
||||
`;
|
||||
|
@ -187,8 +248,14 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveJSProperty("max", "10");
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -201,8 +268,16 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "10");
|
||||
});
|
||||
|
||||
test('should fire a "change" event when the internal control emits a "change" event', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should fire a "change" event when the internal control emits a "change" event', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -225,8 +300,14 @@ test.describe("NumberField", () => {
|
|||
expect(wasChanged).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should fire an "input" event when incrementing or decrementing', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should fire an "input" event when incrementing or decrementing', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -261,8 +342,14 @@ test.describe("NumberField", () => {
|
|||
expect(wasDecreased).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should allow positive float numbers", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow positive float numbers", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -275,8 +362,14 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("1.1");
|
||||
});
|
||||
|
||||
test("should allow negative float numbers", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow negative float numbers", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -289,8 +382,14 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("-1.1");
|
||||
});
|
||||
|
||||
test("should allow positive integer numbers", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow positive integer numbers", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -303,8 +402,14 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("1");
|
||||
});
|
||||
|
||||
test("should allow negative integer numbers", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow negative integer numbers", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -319,8 +424,14 @@ test.describe("NumberField", () => {
|
|||
|
||||
// TODO: This test doesn't account for the `e` character.
|
||||
// See https://github.com/microsoft/fast/issues/6251
|
||||
test("should disallow non-numeric characters", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should disallow non-numeric characters", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -333,8 +444,14 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("");
|
||||
});
|
||||
|
||||
test('should set the `step` property to "1" by default', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should set the `step` property to "1" by default', async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -343,8 +460,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveAttribute("step", "1");
|
||||
});
|
||||
|
||||
test("should update the `step` attribute on the internal control when the `step` property is changed", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the `step` attribute on the internal control when the `step` property is changed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -357,8 +482,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveAttribute("step", "2");
|
||||
});
|
||||
|
||||
test("should increment the `value` property by the step amount when the `stepUp()` method is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should increment the `value` property by the step amount when the `stepUp()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="2" value="5"></fast-number-field>
|
||||
`;
|
||||
|
@ -373,8 +506,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("7");
|
||||
});
|
||||
|
||||
test("should decrement the `value` property by the step amount when the `stepDown()` method is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should decrement the `value` property by the step amount when the `stepDown()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="2" value="5"></fast-number-field>
|
||||
`;
|
||||
|
@ -389,8 +530,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("3");
|
||||
});
|
||||
|
||||
test("should offset an undefined `value` from zero when stepped down", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should offset an undefined `value` from zero when stepped down", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="2"></fast-number-field>
|
||||
`;
|
||||
|
@ -405,8 +554,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("-2");
|
||||
});
|
||||
|
||||
test("should offset an undefined `value` from zero when stepped up", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should offset an undefined `value` from zero when stepped up", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="2"></fast-number-field>
|
||||
`;
|
||||
|
@ -421,8 +578,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("2");
|
||||
});
|
||||
|
||||
test("should offset the `value` from zero after stepping down when `min` is a negative value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should offset the `value` from zero after stepping down when `min` is a negative value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="-10"></fast-number-field>
|
||||
`;
|
||||
|
@ -437,8 +602,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("0");
|
||||
});
|
||||
|
||||
test("should offset the `value` from zero after stepping up when `min` is a negative value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should offset the `value` from zero after stepping up when `min` is a negative value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="-10"></fast-number-field>
|
||||
`;
|
||||
|
@ -453,8 +626,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("0");
|
||||
});
|
||||
|
||||
test("should set `value` to match `min` after stepping down when `min` is greater than 0", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `value` to match `min` after stepping down when `min` is greater than 0", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="10"></fast-number-field>
|
||||
`;
|
||||
|
@ -469,8 +650,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("10");
|
||||
});
|
||||
|
||||
test("should set `value` to match `min` after stepping up when `min` is greater than 0", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set `value` to match `min` after stepping up when `min` is greater than 0", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="10"></fast-number-field>
|
||||
`;
|
||||
|
@ -485,8 +674,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("10");
|
||||
});
|
||||
|
||||
test("should set the `value` to match `max` after stepping down when `value` is undefined and `min` and `max` are less than zero", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `value` to match `max` after stepping down when `value` is undefined and `min` and `max` are less than zero", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="-10" max="-5"></fast-number-field>
|
||||
`;
|
||||
|
@ -501,8 +698,16 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("-5");
|
||||
});
|
||||
|
||||
test("should set the `value` to match `max` after stepping up when `value` is undefined and `min` and `max` are less than zero", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `value` to match `max` after stepping up when `value` is undefined and `min` and `max` are less than zero", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field min="-10" max="-5"></fast-number-field>
|
||||
`;
|
||||
|
@ -517,8 +722,14 @@ test.describe("NumberField", () => {
|
|||
await expect(control).toHaveValue("-5");
|
||||
});
|
||||
|
||||
test("should update the proxy value when stepping down", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the proxy value when stepping down", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="2" value="5"></fast-number-field>
|
||||
`;
|
||||
|
@ -537,8 +748,14 @@ test.describe("NumberField", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should update the proxy value when stepping up", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the proxy value when stepping up", async ({ page }) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="2" value="5"></fast-number-field>
|
||||
`;
|
||||
|
@ -557,11 +774,17 @@ test.describe("NumberField", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should correct rounding errors when stepping down", async () => {
|
||||
test("should correct rounding errors when stepping down", async ({ page }) => {
|
||||
const step = 0.1;
|
||||
const value = 0.2;
|
||||
|
||||
await root.evaluate(
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { step, value }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field step="${step}" value="${value}"></fast-number-field>
|
||||
|
@ -581,8 +804,14 @@ test.describe("NumberField", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should not render step controls when `hide-step` attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not render step controls when `hide-step` attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field hide-step></fast-number-field>
|
||||
`;
|
||||
|
@ -593,8 +822,14 @@ test.describe("NumberField", () => {
|
|||
await expect(controls).toBeHidden();
|
||||
});
|
||||
|
||||
test("should not render step controls when `readonly` attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should not render step controls when `readonly` attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field readonly></fast-number-field>
|
||||
`;
|
||||
|
@ -605,8 +840,14 @@ test.describe("NumberField", () => {
|
|||
await expect(controls).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("should allow setting `valueAsNumber` property with a number", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow setting `valueAsNumber` property with a number", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field></fast-number-field>
|
||||
`;
|
||||
|
@ -619,8 +860,14 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "18");
|
||||
});
|
||||
|
||||
test("should allow reading the `valueAsNumber` property as number", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow reading the `valueAsNumber` property as number", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-number-field value="18"></fast-number-field>
|
||||
`;
|
||||
|
@ -630,10 +877,16 @@ test.describe("NumberField", () => {
|
|||
});
|
||||
|
||||
test.describe("when the owning form's reset() method is invoked", () => {
|
||||
test('should reset its `value` property to "" if no `value` attribute is set', async () => {
|
||||
test('should reset its `value` property to "" if no `value` attribute is set', async ({
|
||||
page,
|
||||
}) => {
|
||||
const form = page.locator("form");
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-number-field></fast-number-field>
|
||||
|
@ -652,10 +905,16 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "");
|
||||
});
|
||||
|
||||
test("should reset the `value` property to match the `value` attribute", async () => {
|
||||
test("should reset the `value` property to match the `value` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const form = page.locator("form");
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-number-field value="10"></fast-number-field>
|
||||
|
@ -676,10 +935,16 @@ test.describe("NumberField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "10");
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async () => {
|
||||
test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
const form = page.locator("form");
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-number-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-number-field value="10"></fast-number-field>
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
export { tagFor, TemplateElementDependency } from "./tag-for.js";
|
||||
export { tagFor } from "../patterns/tag-for.js";
|
||||
export type { TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
export { ARIAGlobalStatesAndProperties } from "./aria-global.js";
|
||||
export {
|
||||
EndOptions,
|
||||
endSlotTemplate,
|
||||
StartEnd,
|
||||
StartEndOptions,
|
||||
StartOptions,
|
||||
startSlotTemplate,
|
||||
} from "./start-end.js";
|
||||
export { endSlotTemplate, StartEnd, startSlotTemplate } from "./start-end.js";
|
||||
export type { EndOptions, StartEndOptions, StartOptions } from "./start-end.js";
|
||||
|
|
|
@ -5,7 +5,8 @@ import {
|
|||
ViewTemplate,
|
||||
when,
|
||||
} from "@microsoft/fast-element";
|
||||
import { tagFor, TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
import type { TemplateElementDependency } from "../patterns/tag-for.js";
|
||||
import { tagFor } from "../patterns/tag-for.js";
|
||||
import type { FASTPicker } from "./picker.js";
|
||||
|
||||
function defaultListItemTemplate(options: PickerOptions): ViewTemplate {
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
|
||||
test.describe("Progress ring", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test.describe("Progress Ring", () => {
|
||||
test("should include a role of progressbar", async ({ page }) => {
|
||||
const element = page.locator("fast-progress-ring");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-progress-ring");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("progress-progress-ring--progress-ring"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of progressbar", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress-ring></fast-progress-ring>
|
||||
`;
|
||||
|
@ -31,8 +15,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("role", "progressbar");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuenow` attribute with the `value` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuenow` attribute with the `value` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress-ring");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress-ring value="50"></fast-progress-ring>
|
||||
`;
|
||||
|
@ -41,8 +31,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuenow", "50");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuemin` attribute with the `min` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuemin` attribute with the `min` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress-ring");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress-ring min="10"></fast-progress-ring>
|
||||
`;
|
||||
|
@ -51,8 +47,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuemin", "10");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuemax` attribute with the `max` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuemax` attribute with the `max` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress-ring");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress-ring max="75"></fast-progress-ring>
|
||||
`;
|
||||
|
@ -61,8 +63,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuemax", "75");
|
||||
});
|
||||
|
||||
test("should render an element with a `determinate` slot when a value is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an element with a `determinate` slot when a value is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress-ring");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress-ring value="50"></fast-progress-ring>
|
||||
`;
|
||||
|
|
|
@ -1,33 +1,29 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTProgress } from "./progress.js";
|
||||
|
||||
test.describe("Progress ring", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test.describe("Progress", () => {
|
||||
test("should include a role of progressbar", async ({ page }) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-progress");
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress></fast-progress>
|
||||
`;
|
||||
});
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("progress--progress"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of progressbar", async () => {
|
||||
await expect(element).toHaveAttribute("role", "progressbar");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuenow` attribute with the `value` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuenow` attribute with the `value` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress value="50"></fast-progress>
|
||||
`;
|
||||
|
@ -36,8 +32,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuenow", "50");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuemin` attribute with the `min` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuemin` attribute with the `min` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress min="50"></fast-progress>
|
||||
`;
|
||||
|
@ -46,8 +48,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuemin", "50");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuemax` attribute with the `max` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuemax` attribute with the `max` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress max="50"></fast-progress>
|
||||
`;
|
||||
|
@ -56,8 +64,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuemax", "50");
|
||||
});
|
||||
|
||||
test("should render an element with a `determinate` slot when a value is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an element with a `determinate` slot when a value is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress value="50"></fast-progress>
|
||||
`;
|
||||
|
@ -68,8 +82,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(progress).toHaveAttribute("slot", "determinate");
|
||||
});
|
||||
|
||||
test("should render an element with an `indeterminate` slot when no value is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an element with an `indeterminate` slot when no value is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress></fast-progress>
|
||||
`;
|
||||
|
@ -80,8 +100,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(progress).toHaveAttribute("slot", "indeterminate");
|
||||
});
|
||||
|
||||
test("should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the `percentComplete` property as a value between 0 and 100 when `min` and `max` are unset", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress value="50"></fast-progress>
|
||||
`;
|
||||
|
@ -90,8 +116,14 @@ test.describe("Progress ring", () => {
|
|||
await expect(element).toHaveJSProperty("percentComplete", 50);
|
||||
});
|
||||
|
||||
test("should set the `percentComplete` property to match the current `value` in the range of `min` and `max`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `percentComplete` property to match the current `value` in the range of `min` and `max`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-progress");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-progress value="0"></fast-progress>
|
||||
`;
|
||||
|
|
|
@ -1,34 +1,16 @@
|
|||
import type { Locator } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import type { FASTRadio } from "../radio/index.js";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import { RadioGroupOrientation } from "./radio-group.options.js";
|
||||
import type { FASTRadioGroup } from "./radio-group.js";
|
||||
import { RadioGroupOrientation } from "./radio-group.options.js";
|
||||
|
||||
test.describe("Radio Group", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let radios: Locator;
|
||||
test("should have a role of `radiogroup`", async ({ page }) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-radio-group");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto(fixtureURL("radio-group--radio-group"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `radiogroup`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -37,8 +19,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(element).toHaveAttribute("role", "radiogroup");
|
||||
});
|
||||
|
||||
test("should set a default `aria-orientation` value when `orientation` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `aria-orientation` value when `orientation` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -50,8 +38,14 @@ test.describe("Radio Group", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should set a matching class on the `positioning-region` when an orientation is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a matching class on the `positioning-region` when an orientation is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -75,8 +69,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(positioningRegion).toHaveClass(/horizontal/);
|
||||
});
|
||||
|
||||
test("should set the `aria-orientation` attribute equal to the `orientation` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-orientation` attribute equal to the `orientation` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -101,8 +101,12 @@ test.describe("Radio Group", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute when disabled", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute when disabled", async ({ page }) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group disabled></fast-radio-group>
|
||||
`;
|
||||
|
@ -111,8 +115,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "true");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -133,8 +143,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-readonly` attribute when the `readonly` attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-readonly` attribute when the `readonly` attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group readonly></fast-radio-group>
|
||||
`;
|
||||
|
@ -143,8 +159,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(element).toHaveAttribute("aria-readonly", "true");
|
||||
});
|
||||
|
||||
test("should set the `aria-readonly` attribute equal to the `readonly` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-readonly` attribute equal to the `readonly` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -165,8 +187,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(element).toHaveAttribute("aria-readonly", "false");
|
||||
});
|
||||
|
||||
test("should NOT set a default `aria-disabled` value when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a default `aria-disabled` value when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group></fast-radio-group>
|
||||
`;
|
||||
|
@ -175,8 +203,16 @@ test.describe("Radio Group", () => {
|
|||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
});
|
||||
|
||||
test("should NOT modify child radio elements disabled state when the `disabled` attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT modify child radio elements disabled state when the `disabled` attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group>
|
||||
<fast-radio></fast-radio>
|
||||
|
@ -243,11 +279,15 @@ test.describe("Radio Group", () => {
|
|||
).toEqual(expectedThird);
|
||||
});
|
||||
|
||||
test("should NOT be focusable when disabled", async () => {
|
||||
test("should NOT be focusable when disabled", async ({ page }) => {
|
||||
const first: Locator = page.locator("button", { hasText: "First" });
|
||||
const second: Locator = page.locator("button", { hasText: "Second" });
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<button>First</button>
|
||||
<fast-radio-group disabled>
|
||||
|
@ -276,8 +316,14 @@ test.describe("Radio Group", () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should NOT be focusable via click when disabled", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT be focusable via click when disabled", async ({ page }) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<button>Button</button>
|
||||
<fast-radio-group>
|
||||
|
@ -317,8 +363,16 @@ test.describe("Radio Group", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set tabindex of 0 to a child radio with a matching `value`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set tabindex of 0 to a child radio with a matching `value`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group value="foo">
|
||||
<fast-radio value="foo"></fast-radio>
|
||||
|
@ -331,8 +385,16 @@ test.describe("Radio Group", () => {
|
|||
await expect(radios.nth(0)).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should NOT set `tabindex` of 0 to a child radio if its value does not match the radiogroup `value`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set `tabindex` of 0 to a child radio if its value does not match the radiogroup `value`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group value="foo">
|
||||
<fast-radio value="bar"></fast-radio>
|
||||
|
@ -349,8 +411,16 @@ test.describe("Radio Group", () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should set a child radio with a matching `value` to `checked`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a child radio with a matching `value` to `checked`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group value="bar">
|
||||
<fast-radio value="foo"></fast-radio>
|
||||
|
@ -367,8 +437,16 @@ test.describe("Radio Group", () => {
|
|||
await expect(radios.nth(2)).not.toBeChecked();
|
||||
});
|
||||
|
||||
test("should set a child radio with a matching `value` to `checked` when value changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a child radio with a matching `value` to `checked` when value changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group value="foo">
|
||||
<fast-radio value="foo"></fast-radio>
|
||||
|
@ -389,8 +467,16 @@ test.describe("Radio Group", () => {
|
|||
await expect(radios.nth(2)).not.toBeChecked();
|
||||
});
|
||||
|
||||
test("should mark only the last radio defaulted to checked as checked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should mark only the last radio defaulted to checked as checked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group>
|
||||
<fast-radio value="foo" checked></fast-radio>
|
||||
|
@ -413,8 +499,16 @@ test.describe("Radio Group", () => {
|
|||
await expect(radios.nth(2)).toBeChecked();
|
||||
});
|
||||
|
||||
test("should mark radio matching value on radio-group over any checked attributes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should mark radio matching value on radio-group over any checked attributes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group value="foo">
|
||||
<fast-radio value="foo"></fast-radio>
|
||||
|
@ -443,8 +537,14 @@ test.describe("Radio Group", () => {
|
|||
await expect(radios.nth(2)).not.toBeChecked();
|
||||
});
|
||||
|
||||
test("should allow resetting of elements by the parent form", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow resetting of elements by the parent form", async ({ page }) => {
|
||||
const element = page.locator("fast-radio-group");
|
||||
|
||||
const radios = element.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-radio-group>
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export { FASTRadio } from "./radio.js";
|
||||
export type { RadioControl, RadioOptions } from "./radio.js";
|
||||
export { radioTemplate } from "./radio.template.js";
|
||||
export { FASTRadio, RadioControl, RadioOptions } from "./radio.js";
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTRadio } from "./radio.js";
|
||||
|
||||
test.describe("Radio", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should have a role of `radio`", async ({ page }) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-radio");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("radio--radio"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `radio`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -32,8 +16,12 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveAttribute("role", "radio");
|
||||
});
|
||||
|
||||
test("should set ARIA attributes to match the state", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set ARIA attributes to match the state", async ({ page }) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -73,8 +61,12 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set a tabindex of 0 on the element", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a tabindex of 0 on the element", async ({ page }) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -83,18 +75,28 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should NOT set a tabindex when disabled is `true`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a tabindex when disabled is `true`", async ({ page }) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio disabled></fast-radio>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute("tabindex", "");
|
||||
await expect(element).not.toHaveAttribute("tabindex");
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -105,8 +107,14 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveJSProperty("initialValue", "on");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -117,8 +125,14 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -129,8 +143,14 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value property if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value property if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio value="foo"></fast-radio>
|
||||
`;
|
||||
|
@ -139,8 +159,14 @@ test.describe("Radio", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should set the `label__hidden` class on the internal label when default slotted content does not exist", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `label__hidden` class on the internal label when default slotted content does not exist", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>label</fast-radio>
|
||||
`;
|
||||
|
@ -157,8 +183,12 @@ test.describe("Radio", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should fire an event when spacebar is pressed", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire an event when spacebar is pressed", async ({ page }) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -182,8 +212,12 @@ test.describe("Radio", () => {
|
|||
expect(wasPressed).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should NOT fire events when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT fire events when clicked", async ({ page }) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio>Radio</fast-radio>
|
||||
`;
|
||||
|
@ -206,8 +240,14 @@ test.describe("Radio", () => {
|
|||
expect(wasClicked).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should handle validity when the `required` attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should handle validity when the `required` attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-radio-group>
|
||||
<fast-radio required name="name" value="test">Radio</fast-radio>
|
||||
|
@ -227,8 +267,14 @@ test.describe("Radio", () => {
|
|||
});
|
||||
|
||||
test.describe("whose parent form has its reset() method invoked", () => {
|
||||
test("should set its checked property to false if the checked attribute is unset", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its checked property to false if the checked attribute is unset", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-radio>Radio</fast-radio>
|
||||
|
@ -249,8 +295,14 @@ test.describe("Radio", () => {
|
|||
await expect(element).not.toBeChecked();
|
||||
});
|
||||
|
||||
test("should set its checked property to true if the checked attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its checked property to true if the checked attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-radio checked></fast-radio>
|
||||
|
@ -277,8 +329,14 @@ test.describe("Radio", () => {
|
|||
await expect(element).toBeChecked();
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where `checked` attribute modifications modify the `checked` property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where `checked` attribute modifications modify the `checked` property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-radio");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-radio>Radio</fast-radio>
|
||||
|
|
|
@ -1,31 +1,8 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTSearch } from "./search.js";
|
||||
|
||||
test.describe("Search", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
|
||||
element = page.locator("fast-search");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(".control");
|
||||
|
||||
await page.goto(fixtureURL("search--search"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test.describe("should set the boolean attribute on the internal input", () => {
|
||||
const attributes = {
|
||||
autofocus: true,
|
||||
|
@ -36,8 +13,12 @@ test.describe("Search", () => {
|
|||
};
|
||||
|
||||
for (const attribute of Object.keys(attributes)) {
|
||||
test(`should set ${attribute}`, async () => {
|
||||
await root.evaluate(
|
||||
test(attribute, async ({ page }) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { attribute }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search ${attribute}>Search</fast-search>
|
||||
|
@ -81,8 +62,15 @@ test.describe("Search", () => {
|
|||
|
||||
for (const [attribute, value] of Object.entries(attributes)) {
|
||||
const attrToken = spinalCase(attribute);
|
||||
test(`should set ${attrToken} to ${value}`, async () => {
|
||||
await root.evaluate(node => {
|
||||
|
||||
test(`should set ${attrToken} to ${value}`, async ({ page }) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search>Search</fast-search>
|
||||
`;
|
||||
|
@ -100,8 +88,14 @@ test.describe("Search", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search>Search</fast-search>
|
||||
`;
|
||||
|
@ -110,8 +104,14 @@ test.describe("Search", () => {
|
|||
await expect(element).toHaveJSProperty("value", "");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search value="foo">Search</fast-search>
|
||||
`;
|
||||
|
@ -120,8 +120,14 @@ test.describe("Search", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search>Search</fast-search>
|
||||
`;
|
||||
|
@ -134,8 +140,14 @@ test.describe("Search", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value property if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value property if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const searchElement = document.createElement("fast-search") as FASTSearch;
|
||||
|
@ -146,8 +158,14 @@ test.describe("Search", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should hide the label when no default slotted content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when no default slotted content is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search></fast-search>
|
||||
`;
|
||||
|
@ -158,8 +176,12 @@ test.describe("Search", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when start content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when start content is provided", async ({ page }) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search><span slot="start">Start</span></fast-search>
|
||||
`;
|
||||
|
@ -170,8 +192,12 @@ test.describe("Search", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when end content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when end content is provided", async ({ page }) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search><span slot="end">End</span></fast-search>
|
||||
`;
|
||||
|
@ -182,8 +208,14 @@ test.describe("Search", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when start and end content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when start and end content is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search>
|
||||
<span slot="start">Start</span>
|
||||
|
@ -197,8 +229,14 @@ test.describe("Search", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when space-only text nodes are slotted", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when space-only text nodes are slotted", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search>label</fast-search>
|
||||
`;
|
||||
|
@ -215,15 +253,21 @@ test.describe("Search", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should fire a change event when the internal control emits a change event", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a change event when the internal control emits a change event", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-search>Search</fast-search>
|
||||
`;
|
||||
});
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(
|
||||
node =>
|
||||
|
@ -240,8 +284,14 @@ test.describe("Search", () => {
|
|||
});
|
||||
|
||||
test.describe("when the owning form's reset() method is invoked", () => {
|
||||
test("should reset its `value` property to an empty string when no value attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset its `value` property to an empty string when no value attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-search>Search</fast-search>
|
||||
|
@ -268,8 +318,14 @@ test.describe("Search", () => {
|
|||
await expect(element).toHaveJSProperty("value", "");
|
||||
});
|
||||
|
||||
test("should reset its `value` property to the value of the value attribute if it is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset its `value` property to the value of the value attribute if it is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-search value="test value">Search</fast-search>
|
||||
|
@ -292,8 +348,14 @@ test.describe("Search", () => {
|
|||
await expect(element).toHaveJSProperty("value", "test value");
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-search");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-search>Search</fast-search>
|
||||
|
|
|
@ -1,32 +1,14 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import type { FASTListboxOption } from "../listbox-option/index.js";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTSelect } from "./select.js";
|
||||
|
||||
test.describe("Select", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should have a role of `combobox`", async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-select");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("select--select"), {
|
||||
waitUntil: "load",
|
||||
});
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `combobox`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select></fast-select>
|
||||
`;
|
||||
|
@ -35,8 +17,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("role", "combobox");
|
||||
});
|
||||
|
||||
test("should have a tabindex of 0 when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a tabindex of 0 when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -49,8 +37,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select disabled></fast-select>
|
||||
`;
|
||||
|
@ -65,8 +59,12 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should have the attribute aria-expanded set to false", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have the attribute aria-expanded set to false", async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select></fast-select>
|
||||
`;
|
||||
|
@ -75,8 +73,12 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("aria-expanded", "false");
|
||||
});
|
||||
|
||||
test("should set its value to the first enabled option", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its value to the first enabled option", async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -91,8 +93,12 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("selectedIndex", 0);
|
||||
});
|
||||
|
||||
test("should NOT have a tabindex when `disabled` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT have a tabindex when `disabled` is true", async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select disabled></fast-select>
|
||||
`;
|
||||
|
@ -101,8 +107,14 @@ test.describe("Select", () => {
|
|||
await expect(element).not.hasAttribute("tabindex");
|
||||
});
|
||||
|
||||
test("should set its value to the first enabled option when disabled", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its value to the first enabled option when disabled", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select disabled>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -117,8 +129,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("selectedIndex", 0);
|
||||
});
|
||||
|
||||
test("should select the first option with a `selected` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should select the first option with a `selected` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -133,8 +151,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("selectedIndex", 1);
|
||||
});
|
||||
|
||||
test("should select the first option with a `selected` attribute when disabled", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should select the first option with a `selected` attribute when disabled", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select disabled>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -149,8 +173,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("selectedIndex", 1);
|
||||
});
|
||||
|
||||
test("should return the same value when the `value` property is set before connect", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the same value when the `value` property is set before connect", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select value="Option 2">
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -163,8 +193,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("value", "Option 2");
|
||||
});
|
||||
|
||||
test("should return the same value when the value property is set after connect", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the same value when the value property is set after connect", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -181,8 +217,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("value", "Option 3");
|
||||
});
|
||||
|
||||
test("should select the next selectable option when the value is set to match a disabled option", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should select the next selectable option when the value is set to match a disabled option", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -205,8 +247,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("selectedIndex", 2);
|
||||
});
|
||||
|
||||
test("should update the `value` property when the selected option's `value` property changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the `value` property when the selected option's `value` property changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -227,8 +275,12 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("value", "new value");
|
||||
});
|
||||
|
||||
test("should return the `value` property as a string", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should return the `value` property as a string", async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option value="1">Option 1</fast-option>
|
||||
|
@ -245,8 +297,12 @@ test.describe("Select", () => {
|
|||
).toBe("string");
|
||||
});
|
||||
|
||||
test("should update the aria-expanded attribute when opened", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the aria-expanded attribute when opened", async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -265,8 +321,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("aria-expanded", "true");
|
||||
});
|
||||
|
||||
test("should display the listbox when the `open` property is true before connecting", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should display the listbox when the `open` property is true before connecting", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select open>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -290,8 +352,14 @@ test.describe("Select", () => {
|
|||
{ expectedValue: "Option 3", key: "End" },
|
||||
{ expectedValue: "Option 1", key: "Home" },
|
||||
].forEach(({ expectedValue, key }) => {
|
||||
test(`should NOT emit \`${eventName}\` event while open when the value changes by user input via ${key} key`, async () => {
|
||||
await root.evaluate(node => {
|
||||
test(`should NOT emit \`${eventName}\` event while open when the value changes by user input via ${key} key`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select open>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -329,8 +397,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveJSProperty("value", expectedValue);
|
||||
});
|
||||
|
||||
test(`should emit \`${eventName}\` event while closed when the value changes by user input via ${key} key`, async () => {
|
||||
await root.evaluate(node => {
|
||||
test(`should emit \`${eventName}\` event while closed when the value changes by user input via ${key} key`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -361,8 +435,20 @@ test.describe("Select", () => {
|
|||
|
||||
test.describe("when the value changes by programmatic interaction", () => {
|
||||
["input", "change"].forEach(eventName => {
|
||||
test(`should NOT emit \`${eventName}\` event`, async () => {
|
||||
await page.goto(fixtureURL("select--select"));
|
||||
test(`should NOT emit \`${eventName}\` event`, async ({ page }) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
<fast-option>Option 2</fast-option>
|
||||
<fast-option>Option 3</fast-option>
|
||||
</fast-select>
|
||||
`;
|
||||
});
|
||||
|
||||
const [wasChanged] = await Promise.all([
|
||||
element.evaluate(
|
||||
|
@ -383,7 +469,7 @@ test.describe("Select", () => {
|
|||
),
|
||||
|
||||
element.evaluate<void, FASTSelect>(node => {
|
||||
node.value = "Tom Baker";
|
||||
node.value = "Option 2";
|
||||
}),
|
||||
]);
|
||||
|
||||
|
@ -393,8 +479,14 @@ test.describe("Select", () => {
|
|||
});
|
||||
|
||||
test.describe("when the owning form's reset() function is invoked", () => {
|
||||
test("should reset the value property to the first available option", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset the value property to the first available option", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-select>
|
||||
|
@ -424,8 +516,14 @@ test.describe("Select", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should set the `aria-activedescendant` attribute to the ID of the currently selected option", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-activedescendant` attribute to the ID of the currently selected option", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option id="option-1">Option 1</fast-option>
|
||||
|
@ -450,8 +548,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("aria-activedescendant", "option-3");
|
||||
});
|
||||
|
||||
test("should set the `aria-controls` attribute to the ID of the internal listbox element while open", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-controls` attribute to the ID of the internal listbox element while open", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
@ -480,8 +584,14 @@ test.describe("Select", () => {
|
|||
await expect(element).toHaveAttribute("aria-controls", "");
|
||||
});
|
||||
|
||||
test("should update the `displayValue` when the selected option's content changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the `displayValue` when the selected option's content changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-select");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-select>
|
||||
<fast-option>Option 1</fast-option>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { css, ElementStyles } from "@microsoft/fast-element";
|
||||
import chevronIcon from "../../../statics/svg/chevron_down_12_regular.svg";
|
||||
import indicator from "../../../statics/svg/chevron_down_12_regular.svg";
|
||||
import { FASTSelect } from "../select.js";
|
||||
import { selectTemplate } from "../select.template.js";
|
||||
|
||||
|
@ -12,6 +12,7 @@ const styles = css`
|
|||
border: calc(var(--stroke-width) * 1px) solid var(--accent-fill-rest);
|
||||
box-sizing: border-box;
|
||||
color: var(--neutral-foreground-rest);
|
||||
fill: currentcolor;
|
||||
font-family: var(--body-font);
|
||||
height: calc(var(--height-number) * 1px);
|
||||
position: relative;
|
||||
|
@ -206,7 +207,7 @@ export class Select extends FASTSelect {
|
|||
Select.define({
|
||||
name: "fast-select",
|
||||
template: selectTemplate({
|
||||
indicator: chevronIcon,
|
||||
indicator,
|
||||
}),
|
||||
styles,
|
||||
});
|
||||
|
|
|
@ -1,30 +1,16 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTSliderLabel } from "./slider-label.js";
|
||||
|
||||
// TODO: Need to add tests for positioning and slider configuration
|
||||
test.describe("Slider label", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should NOT set the `aria-disabled` attribute when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider-label");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-slider-label");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("slider-label--slider-label"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should NOT set the `aria-disabled` attribute when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider-label></fast-slider-label>
|
||||
`;
|
||||
|
@ -33,8 +19,14 @@ test.describe("Slider label", () => {
|
|||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute when the `disabled` property is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute when the `disabled` property is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider-label");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider-label disabled></fast-slider-label>
|
||||
`;
|
||||
|
|
|
@ -1,33 +1,16 @@
|
|||
import { Direction } from "@microsoft/fast-web-utilities";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTSlider } from "./slider.js";
|
||||
import { SliderOrientation } from "./slider.options.js";
|
||||
|
||||
// TODO: Need to add tests for keyboard handling, position, and focus management
|
||||
test.describe("Slider", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
test("should have a role of `slider`", async ({ page }) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
let root: Locator;
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
|
||||
await page.goto(fixtureURL("slider--slider"));
|
||||
|
||||
element = page.locator("fast-slider");
|
||||
|
||||
root = page.locator("#root");
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `slider`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -35,8 +18,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("role", "slider");
|
||||
});
|
||||
|
||||
test("should set a default `min` property of 0 when `min` is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `min` property of 0 when `min` is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -45,8 +34,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("min", 0);
|
||||
});
|
||||
|
||||
test("should set a default `max` property of 0 when `max` is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `max` property of 0 when `max` is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -55,8 +50,12 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("max", "10");
|
||||
});
|
||||
|
||||
test("should set a `tabindex` of 0", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a `tabindex` of 0", async ({ page }) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -65,8 +64,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should NOT set a default `aria-disabled` value when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a default `aria-disabled` value when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -75,8 +80,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
});
|
||||
|
||||
test("should set a default `aria-orientation` value when `orientation` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `aria-orientation` value when `orientation` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -88,8 +99,14 @@ test.describe("Slider", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should NOT set a default `aria-readonly` value when `readonly` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a default `aria-readonly` value when `readonly` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -98,8 +115,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).not.hasAttribute("aria-readonly");
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -112,8 +135,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", initialValue);
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute when `disabled` value is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute when `disabled` value is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -126,8 +155,12 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "true");
|
||||
});
|
||||
|
||||
test("should NOT set a tabindex when `disabled` value is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a tabindex when `disabled` value is true", async ({ page }) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -140,8 +173,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).not.toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should set the `aria-readonly` attribute when `readonly` value is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-readonly` attribute when `readonly` value is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -154,8 +193,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-readonly", "true");
|
||||
});
|
||||
|
||||
test("should set the `aria-orientation` attribute equal to the `orientation` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-orientation` attribute equal to the `orientation` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -180,8 +225,12 @@ test.describe("Slider", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should set direction equal to the `direction` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set direction equal to the `direction` value", async ({ page }) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -200,8 +249,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("direction", Direction.rtl);
|
||||
});
|
||||
|
||||
test("should set the `aria-valuenow` attribute with the `value` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuenow` attribute with the `value` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -214,8 +269,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuenow", "8");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuemin` attribute with the `min` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuemin` attribute with the `min` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -228,8 +289,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuemin", "0");
|
||||
});
|
||||
|
||||
test("should set the `aria-valuemax` attribute with the `max` property when provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-valuemax` attribute with the `max` property when provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -243,8 +310,12 @@ test.describe("Slider", () => {
|
|||
});
|
||||
|
||||
test.describe("valueAsNumber", () => {
|
||||
test("should allow setting value with number", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow setting value with number", async ({ page }) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -257,8 +328,12 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "8");
|
||||
});
|
||||
|
||||
test("should allow reading value as number", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should allow reading value as number", async ({ page }) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -272,8 +347,14 @@ test.describe("Slider", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should set an `aria-valuestring` attribute with the result of the valueTextFormatter() method", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set an `aria-valuestring` attribute with the result of the valueTextFormatter() method", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -287,8 +368,14 @@ test.describe("Slider", () => {
|
|||
});
|
||||
|
||||
test.describe("increment and decrement methods", () => {
|
||||
test("should increment the value when the `increment()` method is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should increment the value when the `increment()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider min="0" max="100" value="50" step="5"></fast-slider>
|
||||
`;
|
||||
|
@ -305,8 +392,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuenow", "55");
|
||||
});
|
||||
|
||||
test("should decrement the value when the `decrement()` method is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should decrement the value when the `decrement()` method is invoked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider min="0" max="100" value="50" step="5"></fast-slider>
|
||||
`;
|
||||
|
@ -321,8 +414,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuenow", "45");
|
||||
});
|
||||
|
||||
test("should increment the value when the `increment()` method is invoked and step is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should increment the value when the `increment()` method is invoked and step is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider min="0" max="100" value="50"></fast-slider>
|
||||
`;
|
||||
|
@ -339,8 +438,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveAttribute("aria-valuenow", "51");
|
||||
});
|
||||
|
||||
test("should decrement the value when the `decrement()` method is invoked and step is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should decrement the value when the `decrement()` method is invoked and step is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider min="0" max="100" value="50"></fast-slider>
|
||||
`;
|
||||
|
@ -356,8 +461,14 @@ test.describe("Slider", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("should increase or decrease the slider value on arrow left/right keys", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should increase or decrease the slider value on arrow left/right keys", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-slider min="0" max="100"></fast-slider>
|
||||
|
@ -386,8 +497,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "7");
|
||||
});
|
||||
|
||||
test("should increase or decrease the slider value on arrow up/down keys", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should increase or decrease the slider value on arrow up/down keys", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-slider min="0" max="100"></fast-slider>
|
||||
|
@ -416,8 +533,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "7");
|
||||
});
|
||||
|
||||
test("should constrain and normalize the value between `min` and `max` when the value is out of range", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should constrain and normalize the value between `min` and `max` when the value is out of range", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider min="0" max="100"></fast-slider>
|
||||
`;
|
||||
|
@ -438,8 +561,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "0");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider value="4"></fast-slider>
|
||||
`;
|
||||
|
@ -450,8 +579,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "4");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider></fast-slider>
|
||||
`;
|
||||
|
@ -464,8 +599,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "3");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value property if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value property if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const slider = document.createElement("fast-slider") as FASTSlider;
|
||||
|
@ -476,8 +617,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "3");
|
||||
});
|
||||
|
||||
test("should update the `stepMultiplier` when the `step` attribute has been updated", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update the `stepMultiplier` when the `step` attribute has been updated", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-slider step="2" value="4"></fast-slider>
|
||||
`;
|
||||
|
@ -498,8 +645,14 @@ test.describe("Slider", () => {
|
|||
});
|
||||
|
||||
test.describe("when the owning form's reset() method is invoked", () => {
|
||||
test("should reset its `value` property to the midpoint if no `value` attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset its `value` property to the midpoint if no `value` attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-slider></fast-slider>
|
||||
|
@ -513,7 +666,7 @@ test.describe("Slider", () => {
|
|||
node.value = "3";
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute("value", "");
|
||||
await expect(element).not.toHaveAttribute("value");
|
||||
|
||||
await expect(element).toHaveJSProperty("value", "3");
|
||||
|
||||
|
@ -524,8 +677,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "5");
|
||||
});
|
||||
|
||||
test("should reset its `value` property to match the `value` attribute when it is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset its `value` property to match the `value` attribute when it is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-slider min="0" max="100"></fast-slider>
|
||||
|
@ -544,6 +703,7 @@ test.describe("Slider", () => {
|
|||
});
|
||||
|
||||
await expect(element).toHaveAttribute("value", "7");
|
||||
|
||||
await expect(element).toHaveJSProperty("value", "8");
|
||||
|
||||
await form.evaluate<void, HTMLFormElement>(node => {
|
||||
|
@ -553,8 +713,14 @@ test.describe("Slider", () => {
|
|||
await expect(element).toHaveJSProperty("value", "7");
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where the value attribute changes the value property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where the value attribute changes the value property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-slider");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-slider min="0" max="100"></fast-slider>
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTSwitch } from "./switch.js";
|
||||
|
||||
test.describe("Switch", () => {
|
||||
let page: Page;
|
||||
let root: Locator;
|
||||
let element: Locator;
|
||||
test("should have a role of `switch`", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-switch");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("switch--switch"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `switch`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -32,8 +16,12 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("role", "switch");
|
||||
});
|
||||
|
||||
test("should set a tabindex of 0 on the element", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a tabindex of 0 on the element", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -42,8 +30,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should set a default `aria-checked` value when `checked` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `aria-checked` value when `checked` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -52,8 +46,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should set a default `aria-disabled` value when `disabled` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default `aria-disabled` value when `disabled` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -62,8 +62,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should NOT set a default `aria-readonly` value when `readonly` is not defined", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a default `aria-readonly` value when `readonly` is not defined", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -72,8 +78,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).not.hasAttribute("aria-readonly");
|
||||
});
|
||||
|
||||
test("should set the `aria-checked` attribute equal to the `checked` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-checked` attribute equal to the `checked` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -92,8 +104,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("aria-checked", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-readonly` attribute equal to the `readonly` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-readonly` attribute equal to the `readonly` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -112,8 +130,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("aria-readonly", "false");
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -126,8 +150,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveJSProperty("value", initialValue);
|
||||
});
|
||||
|
||||
test("should add a class of `label` to the internal label when default slotted content exists", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add a class of `label` to the internal label when default slotted content exists", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -143,8 +173,14 @@ test.describe("Switch", () => {
|
|||
await expect(label).not.toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should add classes of `label` and `label__hidden` to the internal label when default slotted content exists", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should add classes of `label` and `label__hidden` to the internal label when default slotted content exists", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch>Switch</fast-switch>
|
||||
`;
|
||||
|
@ -161,8 +197,14 @@ test.describe("Switch", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -181,8 +223,12 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should NOT set a tabindex when disabled is `true`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set a tabindex when disabled is `true`", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch disabled></fast-switch>
|
||||
`;
|
||||
|
@ -197,8 +243,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch value="foo"></fast-switch>
|
||||
`;
|
||||
|
@ -207,8 +259,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -221,8 +279,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value property if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value property if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const switchElement = document.createElement("fast-switch") as FASTSwitch;
|
||||
|
@ -233,8 +297,12 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foobar");
|
||||
});
|
||||
|
||||
test("should emit an event when clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should emit an event when clicked", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -255,8 +323,12 @@ test.describe("Switch", () => {
|
|||
expect(wasClicked).toBe(true);
|
||||
});
|
||||
|
||||
test("should fire an event when spacebar is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire an event when spacebar is invoked", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -277,8 +349,12 @@ test.describe("Switch", () => {
|
|||
expect(wasEmitted).toBe(true);
|
||||
});
|
||||
|
||||
test("should fire an event when enter is invoked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire an event when enter is invoked", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-switch></fast-switch>
|
||||
`;
|
||||
|
@ -299,8 +375,12 @@ test.describe("Switch", () => {
|
|||
expect(wasEmitted).toBe(true);
|
||||
});
|
||||
|
||||
test("should be invalid when required and unchecked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should be invalid when required and unchecked", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-switch required></fast-switch>
|
||||
|
@ -315,8 +395,12 @@ test.describe("Switch", () => {
|
|||
).toBe(true);
|
||||
});
|
||||
|
||||
test("should be valid when required and checked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should be valid when required and checked", async ({ page }) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-switch required checked></fast-switch>
|
||||
|
@ -332,8 +416,14 @@ test.describe("Switch", () => {
|
|||
});
|
||||
|
||||
test.describe("who's parent form has it's reset() method invoked", () => {
|
||||
test("should set its checked property to false if the checked attribute is unset", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its checked property to false if the checked attribute is unset", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-switch></fast-switch>
|
||||
|
@ -358,8 +448,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveJSProperty("checked", false);
|
||||
});
|
||||
|
||||
test("should set its checked property to true if the checked attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set its checked property to true if the checked attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-switch checked></fast-switch>
|
||||
|
@ -384,8 +480,14 @@ test.describe("Switch", () => {
|
|||
await expect(element).toHaveJSProperty("checked", true);
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where `checked` attribute modifications update the `checked` property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where `checked` attribute modifications update the `checked` property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-switch");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-switch></fast-switch>
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
|
||||
test.describe("TabPanel", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should have a role of `tabpanel`", async ({ page }) => {
|
||||
const element = page.locator("fast-tab-panel");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-tab-panel");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("tabs-tab-panel--tab-panel"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have a role of `tabpanel`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tab-panel></fast-tab-panel>
|
||||
`;
|
||||
|
@ -31,8 +15,12 @@ test.describe("TabPanel", () => {
|
|||
await expect(element).toHaveAttribute("role", "tabpanel");
|
||||
});
|
||||
|
||||
test("should have a slot attribute of `tabpanel`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a slot attribute of `tabpanel`", async ({ page }) => {
|
||||
const element = page.locator("fast-tab-panel");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tab-panel></fast-tab-panel>
|
||||
`;
|
||||
|
|
|
@ -1,47 +1,60 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTTab } from "./tab.js";
|
||||
|
||||
test.describe("Tab", () => {
|
||||
test.describe("States, attributes, and properties", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
test("should have a role of `tab`", async ({ page }) => {
|
||||
const element = page.locator("fast-tab");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.goto(fixtureURL("tabs-tab--tab"));
|
||||
|
||||
element = page.locator("fast-tab");
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tab></fast-tab>
|
||||
`;
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
await expect(element).toHaveAttribute("role", "tab");
|
||||
});
|
||||
|
||||
test("should have a slot attribute of `tab`", async ({ page }) => {
|
||||
const element = page.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tab></fast-tab>
|
||||
`;
|
||||
});
|
||||
|
||||
test("should have a role of `tab`", async () => {
|
||||
await expect(element).toHaveAttribute("role", "tab");
|
||||
await expect(element).toHaveAttribute("slot", "tab");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute when `disabled` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tab></fast-tab>
|
||||
`;
|
||||
});
|
||||
|
||||
test("should have a slot attribute of `tab`", async () => {
|
||||
await expect(element).toHaveAttribute("slot", "tab");
|
||||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
|
||||
await element.evaluate<void, FASTTab>(node => {
|
||||
node.disabled = true;
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute when `disabled` is true", async () => {
|
||||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
await expect(element).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
await element.evaluate<void, FASTTab>(node => {
|
||||
node.disabled = true;
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute("aria-disabled", "true");
|
||||
|
||||
await element.evaluate<void, FASTTab>(element => {
|
||||
element.disabled = false;
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
await element.evaluate<void, FASTTab>(element => {
|
||||
element.disabled = false;
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { FASTTab } from "../tab/tab.js";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTTabs } from "./tabs.js";
|
||||
|
||||
// TODO: Need to add tests for keyboard handling, activeIndicator position, and focus management
|
||||
test.describe("Tabs", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let tablist: Locator;
|
||||
let tabs: Locator;
|
||||
|
||||
const template = /* html */ `
|
||||
<fast-tabs>
|
||||
<fast-tab>Tab one</fast-tab>
|
||||
|
@ -23,26 +15,14 @@ test.describe("Tabs", () => {
|
|||
</fast-tabs>
|
||||
`;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
test("should have an internal element with a role of `tablist`", async ({ page }) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
element = page.locator("fast-tabs");
|
||||
const tablist = element.locator(".tablist");
|
||||
|
||||
root = page.locator("#root");
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
tablist = element.locator(".tablist");
|
||||
|
||||
tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto(fixtureURL("tabs--tabs"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should have an internal element with a role of `tablist`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs></fast-tabs>
|
||||
`;
|
||||
|
@ -51,8 +31,14 @@ test.describe("Tabs", () => {
|
|||
await expect(tablist).toHaveAttribute("role", "tablist");
|
||||
});
|
||||
|
||||
test("should set a default orientation value of `horizontal` when `orientation` is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set a default orientation value of `horizontal` when `orientation` is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs></fast-tabs>
|
||||
`;
|
||||
|
@ -61,8 +47,16 @@ test.describe("Tabs", () => {
|
|||
await expect(element).toHaveJSProperty("orientation", "horizontal");
|
||||
});
|
||||
|
||||
test("should set an `id` attribute on the active tab when an `id` is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set an `id` attribute on the active tab when an `id` is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs></fast-tabs>
|
||||
`;
|
||||
|
@ -81,8 +75,16 @@ test.describe("Tabs", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set an `id` attribute on tab items with a unique ID when an `id` is NOT provided", async () => {
|
||||
await root.evaluate(
|
||||
test("should set an `id` attribute on tab items with a unique ID when an `id` is NOT provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
|
@ -105,8 +107,16 @@ test.describe("Tabs", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set `aria-labelledby` on the tab panel and `aria-controls` on the tab which corresponds to the matching ID when IDs are NOT provided", async () => {
|
||||
await root.evaluate(
|
||||
test("should set `aria-labelledby` on the tab panel and `aria-controls` on the tab which corresponds to the matching ID when IDs are NOT provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
|
@ -136,8 +146,16 @@ test.describe("Tabs", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should set `aria-labelledby` on the tab panel and `aria-controls` on the tab which corresponds to the matching ID when IDs are NOT provided and additional tabs and panels are added", async () => {
|
||||
await root.evaluate(
|
||||
test("should set `aria-labelledby` on the tab panel and `aria-controls` on the tab which corresponds to the matching ID when IDs are NOT provided and additional tabs and panels are added", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
|
@ -201,106 +219,145 @@ test.describe("Tabs", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test.describe("active tab", () => {
|
||||
test("should set an `aria-selected` attribute on the active tab when `activeid` is provided", async () => {
|
||||
await root.evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
test("should set an `aria-selected` attribute on the active tab when `activeid` is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const secondTab = tabs.nth(1);
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
const secondTabId = (await secondTab.getAttribute("id")) ?? "";
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await element.evaluate((node: FASTTabs, secondTabId) => {
|
||||
node.activeid = secondTabId;
|
||||
}, secondTabId);
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
await expect(secondTab).toHaveAttribute("aria-selected", "true");
|
||||
});
|
||||
const secondTab = tabs.nth(1);
|
||||
|
||||
test("should default the first tab as the active index if `activeid` is NOT provided", async () => {
|
||||
await root.evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
const secondTabId = (await secondTab.getAttribute("id")) ?? "";
|
||||
|
||||
await expect(tabs.nth(0)).toHaveAttribute("aria-selected", "true");
|
||||
await element.evaluate((node: FASTTabs, secondTabId) => {
|
||||
node.activeid = secondTabId;
|
||||
}, secondTabId);
|
||||
|
||||
await expect(element).toHaveJSProperty("activeTabIndex", 0);
|
||||
});
|
||||
|
||||
test("should update `aria-selected` attribute on the active tab when `activeId` is updated", async () => {
|
||||
await root.evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
await expect(tabs.nth(0)).toHaveAttribute("aria-selected", "true");
|
||||
|
||||
const secondTab = tabs.nth(1);
|
||||
|
||||
const secondTabId = (await secondTab.getAttribute("id")) ?? "";
|
||||
|
||||
await element.evaluate((node: FASTTabs, secondTabId) => {
|
||||
node.setAttribute("activeId", secondTabId);
|
||||
}, secondTabId);
|
||||
|
||||
await expect(secondTab).toHaveAttribute("aria-selected", "true");
|
||||
});
|
||||
await expect(secondTab).toHaveAttribute("aria-selected", "true");
|
||||
});
|
||||
|
||||
test.describe("active tabpanel", () => {
|
||||
test("should set an `aria-labelledby` attribute on the tabpanel with a value of the tab id when `activeid` is provided", async () => {
|
||||
await root.evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
test("should default the first tab as the active index if `activeid` is NOT provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const secondTab = tabs.nth(1);
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
const secondTabId = (await secondTab.getAttribute("id")) ?? "";
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
const tabPanels = element.locator("fast-tab-panel");
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
await element.evaluate((node: FASTTabs, secondTabId) => {
|
||||
node.activeid = secondTabId;
|
||||
}, secondTabId);
|
||||
await expect(tabs.nth(0)).toHaveAttribute("aria-selected", "true");
|
||||
|
||||
await expect(tabPanels.nth(1)).toHaveAttribute(
|
||||
"aria-labelledby",
|
||||
secondTabId
|
||||
);
|
||||
});
|
||||
|
||||
test("should set an attribute of hidden if the tabpanel is not active", async () => {
|
||||
await root.evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
const tabPanels = element.locator("fast-tab-panel");
|
||||
|
||||
await expect(tabPanels.nth(0)).not.toHaveBooleanAttribute("hidden");
|
||||
|
||||
await expect(tabPanels.nth(1)).toHaveBooleanAttribute("hidden");
|
||||
|
||||
await expect(tabPanels.nth(2)).toHaveBooleanAttribute("hidden");
|
||||
});
|
||||
await expect(element).toHaveJSProperty("activeTabIndex", 0);
|
||||
});
|
||||
|
||||
test("should not allow selecting a tab that has been disabled after it has been connected", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update `aria-selected` attribute on the active tab when `activeId` is updated", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
await expect(tabs.nth(0)).toHaveAttribute("aria-selected", "true");
|
||||
|
||||
const secondTab = tabs.nth(1);
|
||||
|
||||
const secondTabId = (await secondTab.getAttribute("id")) ?? "";
|
||||
|
||||
await element.evaluate((node: FASTTabs, secondTabId) => {
|
||||
node.setAttribute("activeId", secondTabId);
|
||||
}, secondTabId);
|
||||
|
||||
await expect(secondTab).toHaveAttribute("aria-selected", "true");
|
||||
});
|
||||
|
||||
test("should set an `aria-labelledby` attribute on the tabpanel with a value of the tab id when `activeid` is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
const secondTab = tabs.nth(1);
|
||||
|
||||
const secondTabId = (await secondTab.getAttribute("id")) ?? "";
|
||||
|
||||
const tabPanels = element.locator("fast-tab-panel");
|
||||
|
||||
await element.evaluate((node: FASTTabs, secondTabId) => {
|
||||
node.activeid = secondTabId;
|
||||
}, secondTabId);
|
||||
|
||||
await expect(tabPanels.nth(1)).toHaveAttribute("aria-labelledby", secondTabId);
|
||||
});
|
||||
|
||||
test("should set the `hidden` attribute if the tabpanel is not active", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { template }) => {
|
||||
node.innerHTML = template;
|
||||
},
|
||||
{ template }
|
||||
);
|
||||
|
||||
const tabPanels = element.locator("fast-tab-panel");
|
||||
|
||||
await expect(tabPanels.nth(0)).not.toHaveBooleanAttribute("hidden");
|
||||
|
||||
await expect(tabPanels.nth(1)).toHaveBooleanAttribute("hidden");
|
||||
|
||||
await expect(tabPanels.nth(2)).toHaveBooleanAttribute("hidden");
|
||||
});
|
||||
|
||||
test("should not allow selecting a tab that has been disabled after it has been connected", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs>
|
||||
<fast-tab id="tab-1">Tab one</fast-tab>
|
||||
|
@ -342,10 +399,18 @@ test.describe("Tabs", () => {
|
|||
await expect(element).toHaveJSProperty("activeid", firstTabId);
|
||||
});
|
||||
|
||||
test("should allow selecting tab that has been enabled after it has been connected", async () => {
|
||||
test("should allow selecting tab that has been enabled after it has been connected", async ({
|
||||
page,
|
||||
}) => {
|
||||
test.slow();
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs>
|
||||
<fast-tab>Tab one</fast-tab>
|
||||
|
@ -387,10 +452,16 @@ test.describe("Tabs", () => {
|
|||
await expect(element).toHaveJSProperty("activeid", secondTabId);
|
||||
});
|
||||
|
||||
test("should not allow selecting hidden tab using arrow keys", async () => {
|
||||
test("should not allow selecting hidden tab using arrow keys", async ({ page }) => {
|
||||
test.slow();
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs>
|
||||
<fast-tab>Tab one</fast-tab>
|
||||
|
@ -420,10 +491,16 @@ test.describe("Tabs", () => {
|
|||
await expect(element).toHaveJSProperty("activeid", thirdTabId);
|
||||
});
|
||||
|
||||
test("should not allow selecting hidden tab by pressing End", async () => {
|
||||
test("should not allow selecting hidden tab by pressing End", async ({ page }) => {
|
||||
test.slow();
|
||||
|
||||
await root.evaluate(node => {
|
||||
const element = page.locator("fast-tabs");
|
||||
|
||||
const tabs = element.locator("fast-tab");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tabs>
|
||||
<fast-tab>Tab one</fast-tab>
|
||||
|
|
|
@ -1,31 +1,8 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTTextArea } from "./text-area.js";
|
||||
|
||||
test.describe("TextArea", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
|
||||
element = page.locator("fast-text-area");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(".control");
|
||||
|
||||
await page.goto(fixtureURL("text-area--text-area"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test.describe("should set the boolean attribute on the internal input", () => {
|
||||
const attributes = {
|
||||
autofocus: true,
|
||||
|
@ -36,8 +13,14 @@ test.describe("TextArea", () => {
|
|||
};
|
||||
|
||||
for (const attribute of Object.keys(attributes)) {
|
||||
test(attribute, async () => {
|
||||
await root.evaluate((node, attribute: string) => {
|
||||
test(attribute, async ({ page }) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate((node, attribute: string) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-area ${attribute}></fast-text-area>
|
||||
`;
|
||||
|
@ -81,8 +64,14 @@ test.describe("TextArea", () => {
|
|||
for (const [attribute, value] of Object.entries(attributes)) {
|
||||
const attributeSpinalCase = spinalCase(attribute);
|
||||
|
||||
test(attribute, async () => {
|
||||
await root.evaluate(
|
||||
test(attribute, async ({ page }) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { attributeSpinalCase, value }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-area ${attributeSpinalCase}="${value}"></fast-text-area>
|
||||
|
@ -96,8 +85,14 @@ test.describe("TextArea", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should initialize to the initial value if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the initial value if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-area></fast-text-area>
|
||||
`;
|
||||
|
@ -106,8 +101,14 @@ test.describe("TextArea", () => {
|
|||
await expect(element).toHaveJSProperty("value", "");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-area value="foo"></fast-text-area>
|
||||
`;
|
||||
|
@ -116,8 +117,14 @@ test.describe("TextArea", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value property if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value property if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "";
|
||||
|
||||
const textArea = document.createElement("fast-text-area") as FASTTextArea;
|
||||
|
@ -128,8 +135,14 @@ test.describe("TextArea", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided value attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided value attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-area></fast-text-area>
|
||||
`;
|
||||
|
@ -142,8 +155,16 @@ test.describe("TextArea", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should fire a `change` event when the internal control emits a `change` event", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a `change` event when the internal control emits a `change` event", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-area></fast-text-area>
|
||||
`;
|
||||
|
@ -169,8 +190,14 @@ test.describe("TextArea", () => {
|
|||
});
|
||||
|
||||
test.describe("when the owning form's reset() method is invoked", () => {
|
||||
test("should reset the `value` property to an empty string when no `value` attribute is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset the `value` property to an empty string when no `value` attribute is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-text-area></fast-text-area>
|
||||
|
@ -197,8 +224,14 @@ test.describe("TextArea", () => {
|
|||
await expect(element).toHaveJSProperty("value", "");
|
||||
});
|
||||
|
||||
test("should reset the `value` property to match the `value` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset the `value` property to match the `value` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-text-area value="foo"></fast-text-area>
|
||||
|
@ -225,8 +258,14 @@ test.describe("TextArea", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should put the control into a clean state, where `value` attribute modifications change the `value` property prior to user or programmatic interaction", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-area");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<form>
|
||||
<fast-text-area></fast-text-area>
|
||||
|
|
|
@ -104,35 +104,37 @@ This component is built with the expectation that focus is delegated to the inpu
|
|||
|
||||
#### Fields
|
||||
|
||||
| Name | Privacy | Type | Default | Description | Inherited From |
|
||||
| ------------- | ------- | --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| `readOnly` | public | `boolean` | | When true, the control will be immutable by user interaction. See [readonly HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information. | |
|
||||
| `autofocus` | public | `boolean` | | Indicates that this element should get focus after the page finishes loading. See [autofocus HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautofocus) for more information. | |
|
||||
| `placeholder` | public | `string` | | Sets the placeholder value of the element, generally used to provide a hint to the user. | |
|
||||
| `type` | public | `TextFieldType` | | Allows setting a type or mode of text. | |
|
||||
| `list` | public | `string` | | Allows associating a [datalist](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist) to the element by https://developer.mozilla.org/en-US/docs/Web/API/Element/id. | |
|
||||
| `maxlength` | public | `number` | | The maximum number of characters a user can enter. | |
|
||||
| `minlength` | public | `number` | | The minimum number of characters a user can enter. | |
|
||||
| `pattern` | public | `string` | | A regular expression that the value must match to pass validation. | |
|
||||
| `size` | public | `number` | | Sets the width of the element to a specified number of characters. | |
|
||||
| `spellcheck` | public | `boolean` | | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used. | |
|
||||
| `proxy` | | | | | FormAssociatedTextField |
|
||||
| Name | Privacy | Type | Default | Description | Inherited From |
|
||||
| ----------------- | ------- | ------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
||||
| `readOnly` | public | `boolean` | | When true, the control will be immutable by user interaction. See [readonly HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information. | |
|
||||
| `autofocus` | public | `boolean` | | Indicates that this element should get focus after the page finishes loading. See [autofocus HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautofocus) for more information. | |
|
||||
| `placeholder` | public | `string` | | Sets the placeholder value of the element, generally used to provide a hint to the user. | |
|
||||
| `type` | public | `TextFieldType` | | Allows setting a type or mode of text. | |
|
||||
| `slottedDataList` | public | `HTMLDataListElement[] or undefined` | | The slotted datalist elements. | |
|
||||
| `list` | public | `string` | | Allows associating a [datalist](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist) to the element by https://developer.mozilla.org/en-US/docs/Web/API/Element/id. | |
|
||||
| `maxlength` | public | `number` | | The maximum number of characters a user can enter. | |
|
||||
| `minlength` | public | `number` | | The minimum number of characters a user can enter. | |
|
||||
| `pattern` | public | `string` | | A regular expression that the value must match to pass validation. | |
|
||||
| `size` | public | `number` | | Sets the width of the element to a specified number of characters. | |
|
||||
| `spellcheck` | public | `boolean` | | Controls whether or not to enable spell checking for the input field, or if the default spell checking configuration should be used. | |
|
||||
| `proxy` | | | | | FormAssociatedTextField |
|
||||
|
||||
#### Methods
|
||||
|
||||
| Name | Privacy | Description | Parameters | Return | Inherited From |
|
||||
| -------------------- | --------- | ------------------------------------------------- | ---------- | ------ | -------------- |
|
||||
| `readOnlyChanged` | protected | | | `void` | |
|
||||
| `autofocusChanged` | protected | | | `void` | |
|
||||
| `placeholderChanged` | protected | | | `void` | |
|
||||
| `listChanged` | protected | | | `void` | |
|
||||
| `maxlengthChanged` | protected | | | `void` | |
|
||||
| `minlengthChanged` | protected | | | `void` | |
|
||||
| `patternChanged` | protected | | | `void` | |
|
||||
| `sizeChanged` | protected | | | `void` | |
|
||||
| `spellcheckChanged` | protected | | | `void` | |
|
||||
| `select` | public | Selects all the text in the text field | | `void` | |
|
||||
| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | | `void` | |
|
||||
| Name | Privacy | Description | Parameters | Return | Inherited From |
|
||||
| ------------------------ | --------- | ------------------------------------------------- | ------------------------------------------------------------------------------------ | ------ | -------------- |
|
||||
| `readOnlyChanged` | protected | | | `void` | |
|
||||
| `autofocusChanged` | protected | | | `void` | |
|
||||
| `placeholderChanged` | protected | | | `void` | |
|
||||
| `slottedDataListChanged` | protected | | `prev: HTMLDataListElement[] or undefined, next: HTMLDataListElement[] or undefined` | `void` | |
|
||||
| `listChanged` | protected | | | `void` | |
|
||||
| `maxlengthChanged` | protected | | | `void` | |
|
||||
| `minlengthChanged` | protected | | | `void` | |
|
||||
| `patternChanged` | protected | | | `void` | |
|
||||
| `sizeChanged` | protected | | | `void` | |
|
||||
| `spellcheckChanged` | protected | | | `void` | |
|
||||
| `select` | public | Selects all the text in the text field | | `void` | |
|
||||
| `validate` | public | {@inheritDoc (FormAssociated:interface).validate} | | `void` | |
|
||||
|
||||
#### Events
|
||||
|
||||
|
|
|
@ -112,3 +112,15 @@ export const TextFieldInForm: Story<FASTTextField> = renderComponent(
|
|||
</form>
|
||||
`
|
||||
).bind({});
|
||||
|
||||
export const TextFieldWithDataList: Story<FASTTextField> = renderComponent(
|
||||
html<StoryArgs<FASTTextField>>`
|
||||
<fast-text-field>
|
||||
<datalist id="test" slot="datalist">
|
||||
<option value="test" />
|
||||
<option value="test2" />
|
||||
<option value="test3" />
|
||||
</datalist>
|
||||
</fast-text-field>
|
||||
`
|
||||
).bind({});
|
||||
|
|
|
@ -1,36 +1,18 @@
|
|||
import { spinalCase } from "@microsoft/fast-web-utilities";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTTextField } from "./text-field.js";
|
||||
|
||||
test.describe("TextField", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let control: Locator;
|
||||
let label: Locator;
|
||||
test("should set the `autofocus` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
const control = element.locator(".control");
|
||||
|
||||
element = page.locator("fast-text-field");
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
control = element.locator(".control");
|
||||
|
||||
label = element.locator(".label");
|
||||
|
||||
await page.goto(fixtureURL("debug--blank"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should set the `autofocus` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field autofocus></fast-text-field>
|
||||
`;
|
||||
|
@ -39,8 +21,16 @@ test.describe("TextField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("autofocus");
|
||||
});
|
||||
|
||||
test("should set the `disabled` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `disabled` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field disabled></fast-text-field>
|
||||
`;
|
||||
|
@ -49,8 +39,16 @@ test.describe("TextField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("disabled");
|
||||
});
|
||||
|
||||
test("should set the `readonly` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `readonly` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field readonly></fast-text-field>
|
||||
`;
|
||||
|
@ -59,8 +57,16 @@ test.describe("TextField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("readonly");
|
||||
});
|
||||
|
||||
test("should set the `required` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `required` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field required></fast-text-field>
|
||||
`;
|
||||
|
@ -69,8 +75,16 @@ test.describe("TextField", () => {
|
|||
await expect(control).toHaveBooleanAttribute("required");
|
||||
});
|
||||
|
||||
test("should set the `spellcheck` attribute on the internal control", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `spellcheck` attribute on the internal control", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field spellcheck></fast-text-field>
|
||||
`;
|
||||
|
@ -111,8 +125,16 @@ test.describe("TextField", () => {
|
|||
for (const [attribute, value] of Object.entries(attributes)) {
|
||||
const attrToken = spinalCase(attribute);
|
||||
|
||||
test(`should set the \`${attrToken}\` attribute on the internal control`, async () => {
|
||||
await root.evaluate(
|
||||
test(`should set the \`${attrToken}\` attribute on the internal control`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(
|
||||
(node, { attrToken, value }) => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field ${attrToken}="${value}"></fast-text-field>
|
||||
|
@ -126,8 +148,14 @@ test.describe("TextField", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should initialize to the `initialValue` property if no value property is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the `initialValue` property if no value property is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field></fast-text-field>
|
||||
`;
|
||||
|
@ -140,20 +168,30 @@ test.describe("TextField", () => {
|
|||
await expect(element).toHaveJSProperty("value", initialValue);
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` attribute if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` attribute if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field value="foo"></fast-text-field>
|
||||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` property if set pre-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` property if set pre-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ ``;
|
||||
|
||||
const textField = document.createElement("fast-text-field") as FASTTextField;
|
||||
|
@ -166,8 +204,14 @@ test.describe("TextField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should initialize to the provided `value` attribute if set post-connection", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should initialize to the provided `value` attribute if set post-connection", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field></fast-text-field>
|
||||
`;
|
||||
|
@ -180,16 +224,30 @@ test.describe("TextField", () => {
|
|||
await expect(element).toHaveJSProperty("value", "foo");
|
||||
});
|
||||
|
||||
test("should hide the label when no default slotted content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when no default slotted content is provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const label = element.locator(".label");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = "<fast-text-field></fast-text-field>";
|
||||
});
|
||||
|
||||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when start content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when start content is provided", async ({ page }) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const label = element.locator(".label");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field>
|
||||
<div slot="start"></div>
|
||||
|
@ -200,8 +258,14 @@ test.describe("TextField", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when end content is provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when end content is provided", async ({ page }) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const label = element.locator(".label");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field>
|
||||
<div slot="end"></div>
|
||||
|
@ -212,8 +276,16 @@ test.describe("TextField", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when start and end content are provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when start and end content are provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const label = element.locator(".label");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field>
|
||||
<div slot="start"></div>
|
||||
|
@ -225,8 +297,16 @@ test.describe("TextField", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should hide the label when space-only text nodes are slotted", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should hide the label when space-only text nodes are slotted", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const label = element.locator(".label");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = `<fast-text-field>\n \n</fast-text-field>`;
|
||||
});
|
||||
|
||||
|
@ -235,8 +315,16 @@ test.describe("TextField", () => {
|
|||
await expect(label).toHaveClass(/label__hidden/);
|
||||
});
|
||||
|
||||
test("should fire a `change` event when the internal control emits a `change` event", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a `change` event when the internal control emits a `change` event", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
const control = element.locator(".control");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field></fast-text-field>
|
||||
`;
|
||||
|
@ -262,8 +350,14 @@ test.describe("TextField", () => {
|
|||
});
|
||||
|
||||
test.describe("with a type of `password`", () => {
|
||||
test("should report invalid validity when the `value` property is an empty string and `required` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report invalid validity when the `value` property is an empty string and `required` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" required></fast-text-field>
|
||||
`;
|
||||
|
@ -276,8 +370,14 @@ test.describe("TextField", () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` property is a string that is non-empty and `required` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` property is a string that is non-empty and `required` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" required value="some-value"></fast-text-field>
|
||||
`;
|
||||
|
@ -290,8 +390,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` is empty and `minlength` is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is empty and `minlength` is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" minlength="1"></fast-text-field>
|
||||
`;
|
||||
|
@ -304,8 +410,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` has a length less than `minlength`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` has a length less than `minlength`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" minlength="10" value="123456789"></fast-text-field>
|
||||
`;
|
||||
|
@ -318,8 +430,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` is empty and `maxlength` is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is empty and `maxlength` is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" maxlength="10"></fast-text-field>
|
||||
`;
|
||||
|
@ -332,8 +450,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` has a length which exceeds the `maxlength`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` has a length which exceeds the `maxlength`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" maxlength="10" value="12345678901"></fast-text-field>
|
||||
`;
|
||||
|
@ -346,8 +470,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` is shorter than `maxlength` and the element is `required`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` is shorter than `maxlength` and the element is `required`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" maxlength="10" required value="123456789"></fast-text-field>
|
||||
`;
|
||||
|
@ -360,8 +490,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` property matches the `pattern` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` property matches the `pattern` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" pattern="\\d+" value="123456789"></fast-text-field>
|
||||
`;
|
||||
|
@ -374,15 +510,19 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report invalid validity when `value` does not match `pattern`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report invalid validity when `value` does not match `pattern`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="password" pattern="value" value="other value"></fast-text-field>
|
||||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
expect(
|
||||
await element.evaluate<boolean, FASTTextField>(
|
||||
node => node.validity.patternMismatch
|
||||
|
@ -392,8 +532,14 @@ test.describe("TextField", () => {
|
|||
});
|
||||
|
||||
test.describe("with a type of `tel`", () => {
|
||||
test("should report invalid validity when the `value` property is an empty string and `required` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report invalid validity when the `value` property is an empty string and `required` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" required></fast-text-field>
|
||||
`;
|
||||
|
@ -406,8 +552,14 @@ test.describe("TextField", () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` property is not empty and `required` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` property is not empty and `required` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" required value="some-value"></fast-text-field>
|
||||
`;
|
||||
|
@ -420,8 +572,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `minlength` is set and `value` is an empty string", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `minlength` is set and `value` is an empty string", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" minlength="1"></fast-text-field>
|
||||
`;
|
||||
|
@ -434,8 +592,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the length of `value` is less than `minlength`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the length of `value` is less than `minlength`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" minlength="10" value="123456789"></fast-text-field>
|
||||
`;
|
||||
|
@ -448,8 +612,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` is an empty string", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is an empty string", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" maxlength="10"></fast-text-field>
|
||||
`;
|
||||
|
@ -462,8 +632,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` has a length which exceeds `maxlength`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` has a length which exceeds `maxlength`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" maxlength="10" value="12345678901"></fast-text-field>
|
||||
`;
|
||||
|
@ -476,8 +652,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` is shorter than `maxlength` and the element is `required`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` is shorter than `maxlength` and the element is `required`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" maxlength="10" required value="123456789"></fast-text-field>
|
||||
`;
|
||||
|
@ -490,15 +672,19 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` matches `pattern`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` matches `pattern`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" pattern="\\d+" value="123456789"></fast-text-field>
|
||||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
expect(
|
||||
await element.evaluate<boolean, FASTTextField>(
|
||||
node => node.validity.patternMismatch
|
||||
|
@ -506,15 +692,19 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report invalid validity when `value` does not match `pattern`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report invalid validity when `value` does not match `pattern`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="tel" pattern="value" required value="other value"></fast-text-field>
|
||||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
expect(
|
||||
await element.evaluate<boolean, FASTTextField>(
|
||||
node => node.validity.patternMismatch
|
||||
|
@ -524,8 +714,14 @@ test.describe("TextField", () => {
|
|||
});
|
||||
|
||||
test.describe("with a type of `text`", () => {
|
||||
test("should report invalid validity when the `value` property is an empty string and `required` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report invalid validity when the `value` property is an empty string and `required` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" required></fast-text-field>
|
||||
`;
|
||||
|
@ -538,8 +734,14 @@ test.describe("TextField", () => {
|
|||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` property is not empty and `required` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` property is not empty and `required` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" required value="some value"></fast-text-field>
|
||||
`;
|
||||
|
@ -552,8 +754,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` is an empty string and `minlength` is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is an empty string and `minlength` is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" minlength="1"></fast-text-field>
|
||||
`;
|
||||
|
@ -566,8 +774,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` has a length less than `minlength`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` has a length less than `minlength`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" minlength="6" value="value"></fast-text-field>
|
||||
`;
|
||||
|
@ -580,8 +794,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` is empty and `maxlength` is set", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is empty and `maxlength` is set", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" maxlength="0"></fast-text-field>
|
||||
`;
|
||||
|
@ -594,8 +814,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when `value` has a length which exceeds `maxlength`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` has a length which exceeds `maxlength`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" maxlength="4" value="value"></fast-text-field>
|
||||
`;
|
||||
|
@ -608,8 +834,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` is shorter than `maxlength` and the element is `required`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` is shorter than `maxlength` and the element is `required`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" maxlength="6" required value="value"></fast-text-field>
|
||||
`;
|
||||
|
@ -622,8 +854,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report valid validity when the `value` matches `pattern`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when the `value` matches `pattern`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" pattern="value" required value="value"></fast-text-field>
|
||||
`;
|
||||
|
@ -636,8 +874,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should report invalid validity when `value` does not match `pattern`", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report invalid validity when `value` does not match `pattern`", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="text" pattern="value" required value="other value"></fast-text-field>
|
||||
`;
|
||||
|
@ -652,8 +896,14 @@ test.describe("TextField", () => {
|
|||
});
|
||||
|
||||
test.describe("with a type of `email`", () => {
|
||||
test("should report valid validity when `value` is an empty string", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is an empty string", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="email"></fast-text-field>
|
||||
`;
|
||||
|
@ -666,8 +916,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should have invalid invalidity with a `typeMismatch` when `value` is not a valid email", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have invalid invalidity with a `typeMismatch` when `value` is not a valid email", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="email" value="not an email"></fast-text-field>
|
||||
`;
|
||||
|
@ -682,8 +938,14 @@ test.describe("TextField", () => {
|
|||
});
|
||||
|
||||
test.describe("with a type of `url`", () => {
|
||||
test("should report valid validity when `value` is an empty string", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should report valid validity when `value` is an empty string", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="url"></fast-text-field>
|
||||
`;
|
||||
|
@ -696,8 +958,14 @@ test.describe("TextField", () => {
|
|||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("should have invalid invalidity with a `typeMismatch` when `value` is not a valid URL", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have invalid invalidity with a `typeMismatch` when `value` is not a valid URL", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-text-field");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-text-field type="url" value="not a url"></fast-text-field>
|
||||
`;
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
import { ElementViewTemplate, html, ref, slotted } from "@microsoft/fast-element";
|
||||
import {
|
||||
elements,
|
||||
ElementViewTemplate,
|
||||
html,
|
||||
ref,
|
||||
slotted,
|
||||
} from "@microsoft/fast-element";
|
||||
import { endSlotTemplate, startSlotTemplate } from "../patterns/index.js";
|
||||
import { whitespaceFilter } from "../utilities/whitespace-filter.js";
|
||||
import type { FASTTextField, TextFieldOptions } from "./text-field.js";
|
||||
|
@ -11,6 +17,13 @@ export function textFieldTemplate<T extends FASTTextField>(
|
|||
options: TextFieldOptions = {}
|
||||
): ElementViewTemplate<T> {
|
||||
return html<T>`
|
||||
<slot
|
||||
name="datalist"
|
||||
${slotted({
|
||||
property: "slottedDataList",
|
||||
filter: elements("datalist"),
|
||||
})}
|
||||
></slot>
|
||||
<label
|
||||
part="label"
|
||||
for="control"
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
observable,
|
||||
Updates,
|
||||
} from "@microsoft/fast-element";
|
||||
import { uniqueId } from "@microsoft/fast-web-utilities";
|
||||
import { ARIAGlobalStatesAndProperties, StartEnd } from "../patterns/index.js";
|
||||
import type { StartEndOptions } from "../patterns/start-end.js";
|
||||
import { applyMixins } from "../utilities/apply-mixins.js";
|
||||
|
@ -93,6 +94,30 @@ export class FASTTextField extends FormAssociatedTextField {
|
|||
}
|
||||
}
|
||||
|
||||
private dataList: HTMLDataListElement | undefined;
|
||||
|
||||
/**
|
||||
* The slotted datalist elements.
|
||||
* @public
|
||||
*/
|
||||
@observable
|
||||
public slottedDataList?: HTMLDataListElement[];
|
||||
protected slottedDataListChanged(
|
||||
prev: HTMLDataListElement[] | undefined,
|
||||
next: HTMLDataListElement[] | undefined
|
||||
): void {
|
||||
this.dataList = next?.[0];
|
||||
if (!this.dataList) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dataList.id) {
|
||||
this.dataList.id = uniqueId("datalist-");
|
||||
}
|
||||
|
||||
this.control.setAttribute("list", this.dataList.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows associating a {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist | datalist} to the element by {@link https://developer.mozilla.org/en-US/docs/Web/API/Element/id}.
|
||||
* @public
|
||||
|
|
|
@ -1,36 +1,48 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import { ToolbarOrientation } from "./toolbar.options.js";
|
||||
|
||||
test.describe("Toolbar", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should have a role of `toolbar`", async ({ page }) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-toolbar");
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar></fast-toolbar>
|
||||
`;
|
||||
});
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("toolbar--toolbar"));
|
||||
});
|
||||
|
||||
test("should have a role of `toolbar`", async () => {
|
||||
await expect(element).toHaveAttribute("role", "toolbar");
|
||||
});
|
||||
|
||||
test("should have a default orientation of `horizontal`", async () => {
|
||||
test("should have a default orientation of `horizontal`", async ({ page }) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar></fast-toolbar>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).toHaveAttribute(
|
||||
"orientation",
|
||||
ToolbarOrientation.horizontal
|
||||
);
|
||||
});
|
||||
|
||||
test("should move focus to its first focusable element when it receives focus", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus to its first focusable element when it receives focus", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
const buttons = element.locator("button");
|
||||
const firstButton = buttons.filter({ hasText: "Start Slot Button" });
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button>Button 1</button>
|
||||
|
@ -44,19 +56,20 @@ test.describe("Toolbar", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
const buttons = element.locator("button");
|
||||
|
||||
const firstButton = buttons.filter({ hasText: "Start Slot Button" });
|
||||
|
||||
await element.focus();
|
||||
|
||||
await expect(firstButton).toBeFocused();
|
||||
});
|
||||
|
||||
test("should move focus to next element when keyboard incrementer is pressed", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus to next element when keyboard incrementer is pressed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
const buttons = element.locator("button");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -70,8 +83,6 @@ test.describe("Toolbar", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
const buttons = element.locator("button");
|
||||
|
||||
await element.focus();
|
||||
|
||||
await expect(buttons.filter({ hasText: "Start Slot Button" })).toBeFocused();
|
||||
|
@ -101,8 +112,15 @@ test.describe("Toolbar", () => {
|
|||
await expect(buttons.filter({ hasText: "End Slot Button" })).toBeFocused();
|
||||
});
|
||||
|
||||
test("should skip disabled elements when keyboard incrementer is pressed", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should skip disabled elements when keyboard incrementer is pressed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
const buttons = element.locator("button:not([slot])");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -116,8 +134,6 @@ test.describe("Toolbar", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
const buttons = element.locator("button:not([slot])");
|
||||
|
||||
const startSlotButton = element.locator("button", {
|
||||
hasText: "Start Slot Button",
|
||||
});
|
||||
|
@ -147,8 +163,15 @@ test.describe("Toolbar", () => {
|
|||
await expect(endSlotButton).toBeFocused();
|
||||
});
|
||||
|
||||
test("should skip hidden elements when keyboard incrementer is pressed", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should skip hidden elements when keyboard incrementer is pressed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
const buttons = element.locator("button:not([slot])");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -162,8 +185,6 @@ test.describe("Toolbar", () => {
|
|||
`;
|
||||
});
|
||||
|
||||
const buttons = element.locator("button:not([slot])");
|
||||
|
||||
const startSlotButton = element.locator("button", {
|
||||
hasText: "Start Slot Button",
|
||||
});
|
||||
|
@ -193,8 +214,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(endSlotButton).toBeFocused();
|
||||
});
|
||||
|
||||
test("should move focus to next element when keyboard incrementer is pressed and start slot content is added after connect", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus to next element when keyboard incrementer is pressed and start slot content is added after connect", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `<fast-toolbar></fast-toolbar>`;
|
||||
});
|
||||
|
||||
|
@ -225,8 +252,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(button2).toBeFocused();
|
||||
});
|
||||
|
||||
test("should move focus to next element when keyboard incrementer is pressed and end slot content is added after connect", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should move focus to next element when keyboard incrementer is pressed and end slot content is added after connect", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar></fast-toolbar>
|
||||
`;
|
||||
|
@ -260,8 +293,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(endSlotButton).toBeFocused();
|
||||
});
|
||||
|
||||
test("should maintain correct activeIndex when the set of focusable children changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should maintain correct activeIndex when the set of focusable children changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -304,8 +343,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(element).toHaveJSProperty("activeIndex", 1);
|
||||
});
|
||||
|
||||
test("should reset activeIndex to 0 when the focused item is no longer focusable", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should reset activeIndex to 0 when the focused item is no longer focusable", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -350,8 +395,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(element).toHaveJSProperty("activeIndex", 0);
|
||||
});
|
||||
|
||||
test("should update activeIndex when an element within the toolbar is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update activeIndex when an element within the toolbar is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -382,8 +433,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(element).toHaveJSProperty("activeIndex", 2);
|
||||
});
|
||||
|
||||
test("should update activeIndex when a nested element within the toolbar is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should update activeIndex when a nested element within the toolbar is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -419,8 +476,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(element).toHaveJSProperty("activeIndex", 2);
|
||||
});
|
||||
|
||||
test("should focus most recently focused item when toolbar receives focus", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should focus most recently focused item when toolbar receives focus", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -436,7 +499,9 @@ test.describe("Toolbar", () => {
|
|||
});
|
||||
const button2 = element.locator("button", { hasText: "Button 2" });
|
||||
|
||||
const buttonOutsideToolbar = page.locator("button", { hasText: "Button Outside Toolbar"});
|
||||
const buttonOutsideToolbar = page.locator("button", {
|
||||
hasText: "Button Outside Toolbar",
|
||||
});
|
||||
|
||||
await button2.click();
|
||||
await expect(button2).toBeFocused();
|
||||
|
@ -449,8 +514,14 @@ test.describe("Toolbar", () => {
|
|||
await expect(button2).toBeFocused();
|
||||
});
|
||||
|
||||
test("should focus clicked item when focus enters toolbar by clicking an item that is not the most recently focused item", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should focus clicked item when focus enters toolbar by clicking an item that is not the most recently focused item", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-toolbar");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-toolbar>
|
||||
<button slot="start">Start Slot Button</button>
|
||||
|
@ -468,7 +539,9 @@ test.describe("Toolbar", () => {
|
|||
|
||||
const button3 = element.locator("button", { hasText: "Button 3" });
|
||||
|
||||
const buttonOutsideToolbar = page.locator("button", { hasText: "Button Outside Toolbar"});
|
||||
const buttonOutsideToolbar = page.locator("button", {
|
||||
hasText: "Button Outside Toolbar",
|
||||
});
|
||||
|
||||
await button2.click();
|
||||
await expect(button2).toBeFocused();
|
||||
|
|
|
@ -1,38 +1,30 @@
|
|||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTTooltip } from "./tooltip.js";
|
||||
|
||||
test.describe("Tooltip", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
let anchoredRegion: Locator;
|
||||
test("should not render the tooltip by default", async ({ page }) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
const anchoredRegion = element.locator("fast-anchored-region");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-tooltip");
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip></fast-tooltip>
|
||||
`;
|
||||
});
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
anchoredRegion = element.locator("fast-anchored-region");
|
||||
|
||||
await page.goto(fixtureURL("tooltip--tooltip", { delay: 0 }));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should not render the tooltip by default", async () => {
|
||||
await expect(element).toHaveJSProperty("visible", false);
|
||||
|
||||
await expect(anchoredRegion).toBeHidden();
|
||||
});
|
||||
|
||||
test("should render the tooltip when the anchor is hovered", async () => {
|
||||
await root.evaluate((node: HTMLElement) => {
|
||||
test("should render the tooltip when the anchor is hovered", async ({ page }) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip anchor="anchor-default">
|
||||
Tooltip
|
||||
|
@ -52,8 +44,12 @@ test.describe("Tooltip", () => {
|
|||
await expect(element).toBeVisible();
|
||||
});
|
||||
|
||||
test("should render the tooltip when the anchor is focused", async () => {
|
||||
await root.evaluate((node: HTMLElement) => {
|
||||
test("should render the tooltip when the anchor is focused", async ({ page }) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip anchor="anchor-default">
|
||||
Tooltip
|
||||
|
@ -77,8 +73,14 @@ test.describe("Tooltip", () => {
|
|||
await expect(element).toBeVisible();
|
||||
});
|
||||
|
||||
test('should render the tooltip when the `show` attribute is "true"', async () => {
|
||||
await root.evaluate((node: HTMLElement) => {
|
||||
test('should render the tooltip when the `show` attribute is "true"', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip anchor="anchor-default" show="true">
|
||||
Tooltip
|
||||
|
@ -94,8 +96,14 @@ test.describe("Tooltip", () => {
|
|||
await expect(element).toBeVisible();
|
||||
});
|
||||
|
||||
test('should not render the tooltip when the `show` attribute is "false"', async () => {
|
||||
await root.evaluate((node: HTMLElement) => {
|
||||
test('should not render the tooltip when the `show` attribute is "false"', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip anchor="anchor-default" show="false">
|
||||
Tooltip
|
||||
|
@ -115,8 +123,14 @@ test.describe("Tooltip", () => {
|
|||
await expect(element).toBeHidden();
|
||||
});
|
||||
|
||||
test('should not render the tooltip when the anchor is hovered and `show` is "false"', async () => {
|
||||
await root.evaluate((node: HTMLElement) => {
|
||||
test('should not render the tooltip when the anchor is hovered and `show` is "false"', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip anchor="anchor-default">
|
||||
Tooltip
|
||||
|
@ -144,10 +158,23 @@ test.describe("Tooltip", () => {
|
|||
await expect(element).toBeHidden();
|
||||
});
|
||||
|
||||
test("should change anchor element when the `anchor` attribute changes", async () => {
|
||||
await page.goto(fixtureURL("tooltip--tooltip"));
|
||||
test("should change anchor element when the `anchor` attribute changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tooltip");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tooltip anchor="anchor-default">
|
||||
Tooltip
|
||||
</fast-tooltip>
|
||||
<fast-button id="anchor-default">
|
||||
Hover or focus me
|
||||
</fast-button>
|
||||
`;
|
||||
|
||||
await root.evaluate(node => {
|
||||
const newAnchor = document.createElement("div");
|
||||
newAnchor.id = "new-anchor";
|
||||
|
||||
|
@ -155,7 +182,9 @@ test.describe("Tooltip", () => {
|
|||
});
|
||||
|
||||
expect(
|
||||
await element.evaluate((node: FASTTooltip) => node.anchorElement?.id)
|
||||
await element.evaluate<string | undefined, FASTTooltip>(
|
||||
node => node.anchorElement?.id
|
||||
)
|
||||
).toBe("anchor-default");
|
||||
|
||||
await element.evaluate(node => {
|
||||
|
@ -163,7 +192,9 @@ test.describe("Tooltip", () => {
|
|||
});
|
||||
|
||||
expect(
|
||||
await element.evaluate((node: FASTTooltip) => node.anchorElement?.id)
|
||||
await element.evaluate<string | undefined, FASTTooltip>(
|
||||
node => node.anchorElement?.id
|
||||
)
|
||||
).toBe("new-anchor");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
import type { FASTTreeItem } from "./tree-item.js";
|
||||
|
||||
test.describe("TreeItem", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should include a role of `treeitem`", async ({ page }) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-tree-item");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("tree-view-tree-item--tree-item"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of `treeitem`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -32,8 +16,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("role", "treeitem");
|
||||
});
|
||||
|
||||
test("should set the `aria-expanded` attribute equal to the `expanded` value when the tree item has children", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-expanded` attribute equal to the `expanded` value when the tree item has children", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -54,8 +44,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element.first()).toHaveAttribute("aria-expanded", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-expanded` attribute equal to TRUE when the `expanded` attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-expanded` attribute equal to TRUE when the `expanded` attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item expanded>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -66,44 +62,68 @@ test.describe("TreeItem", () => {
|
|||
await expect(element.first()).toHaveAttribute("aria-expanded", "true");
|
||||
});
|
||||
|
||||
test("should NOT set the `aria-expanded` attribute when the tree item has no children", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set the `aria-expanded` attribute when the tree item has no children", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).not.hasAttribute("aria-expanded");
|
||||
await expect(element).not.toHaveAttribute("aria-expanded");
|
||||
});
|
||||
|
||||
test("should NOT set the `aria-expanded` attribute when the `expanded` state is true and the tree item has no children", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set the `aria-expanded` attribute when the `expanded` state is true and the tree item has no children", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item expanded></fast-tree-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).not.hasAttribute("aria-expanded");
|
||||
await expect(element).not.toHaveAttribute("aria-expanded");
|
||||
|
||||
await element.evaluate<void, FASTTreeItem>(node => {
|
||||
node.expanded = true;
|
||||
});
|
||||
|
||||
await expect(element).not.hasAttribute("aria-expanded");
|
||||
await expect(element).not.toHaveAttribute("aria-expanded");
|
||||
});
|
||||
|
||||
test("should NOT set the `aria-selected` attribute if `selected` value is not provided", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set the `aria-selected` attribute if `selected` value is not provided", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).not.hasAttribute("aria-selected");
|
||||
await expect(element).not.toHaveAttribute("aria-selected");
|
||||
});
|
||||
|
||||
test("should set the `aria-selected` attribute equal to the `selected` value", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-selected` attribute equal to the `selected` value", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -122,8 +142,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("aria-selected", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-selected` attribute equal to TRUE when the selected attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-selected` attribute equal to TRUE when the selected attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item selected>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -138,14 +164,20 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to the `disabled` property", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
});
|
||||
|
||||
await expect(element).not.hasAttribute("aria-disabled");
|
||||
await expect(element).not.toHaveAttribute("aria-disabled");
|
||||
|
||||
await element.evaluate<void, FASTTreeItem>(node => {
|
||||
node.disabled = true;
|
||||
|
@ -160,8 +192,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "false");
|
||||
});
|
||||
|
||||
test("should set the `aria-disabled` attribute equal to TRUE when the disabled attribute is present", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the `aria-disabled` attribute equal to TRUE when the disabled attribute is present", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item disabled>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -170,8 +208,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("aria-disabled", "true");
|
||||
});
|
||||
|
||||
test('should add a slot attribute of "item" to nested tree items', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should add a slot attribute of "item" to nested tree items', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -185,8 +229,12 @@ test.describe("TreeItem", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("should have a default `tabindex` attribute of -1", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a default `tabindex` attribute of -1", async ({ page }) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -195,8 +243,12 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "-1");
|
||||
});
|
||||
|
||||
test("should have a tabindex of 0 when focused", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should have a tabindex of 0 when focused", async ({ page }) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -207,8 +259,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element).toHaveAttribute("tabindex", "0");
|
||||
});
|
||||
|
||||
test("should render an element with a class of `expand-collapse-button` when nested tree items exist", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an element with a class of `expand-collapse-button` when nested tree items exist", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -223,8 +281,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(expandCollapseButton).toHaveAttribute("aria-hidden", "true");
|
||||
});
|
||||
|
||||
test("should render an element with a role of `group` when nested tree items exist and `expanded` is true", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should render an element with a role of `group` when nested tree items exist and `expanded` is true", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item expanded>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -235,8 +299,14 @@ test.describe("TreeItem", () => {
|
|||
await expect(element.first().locator(".items")).toHaveAttribute("role", "group");
|
||||
});
|
||||
|
||||
test("should NOT render an element with a role of `group` when nested tree items exist and `expanded` is false", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT render an element with a role of `group` when nested tree items exist and `expanded` is false", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -248,8 +318,14 @@ test.describe("TreeItem", () => {
|
|||
});
|
||||
|
||||
test.describe("events", () => {
|
||||
test('should emit a "change" event when the `expanded` property changes', async () => {
|
||||
await root.evaluate(node => {
|
||||
test('should emit a "change" event when the `expanded` property changes', async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
|
@ -280,8 +356,14 @@ test.describe("TreeItem", () => {
|
|||
expect(wasClicked).toBe(true);
|
||||
});
|
||||
|
||||
test("should fire a selected change event when the `selected` property changes", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire a selected change event when the `selected` property changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -303,8 +385,14 @@ test.describe("TreeItem", () => {
|
|||
expect(wasChanged).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should NOT set `selected` state when a disabled element is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should NOT set `selected` state when a disabled element is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item disabled>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -314,11 +402,17 @@ test.describe("TreeItem", () => {
|
|||
|
||||
await expect(element).not.toHaveBooleanAttribute("selected");
|
||||
|
||||
await expect(element).not.hasAttribute("aria-selected");
|
||||
await expect(element).not.toHaveAttribute("aria-selected");
|
||||
});
|
||||
|
||||
test("should fire an event when expanded state changes via the `expanded` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire an event when expanded state changes via the `expanded` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
@ -340,8 +434,14 @@ test.describe("TreeItem", () => {
|
|||
expect(wasChanged).toBeTruthy();
|
||||
});
|
||||
|
||||
test("should fire an event when selected state changes via the `selected` attribute", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should fire an event when selected state changes via the `selected` attribute", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-item");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-item>tree item</fast-tree-item>
|
||||
`;
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
import { expect, test } from "@playwright/test";
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { fixtureURL } from "../__test__/helpers.js";
|
||||
|
||||
// TODO: Need to add tests for keyboard handling & focus management
|
||||
test.describe("TreeView", () => {
|
||||
let page: Page;
|
||||
let element: Locator;
|
||||
let root: Locator;
|
||||
test("should include a role of `tree`", async ({ page }) => {
|
||||
const element = page.locator("fast-tree-view");
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
page = await browser.newPage();
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
element = page.locator("fast-tree-view");
|
||||
|
||||
root = page.locator("#root");
|
||||
|
||||
await page.goto(fixtureURL("tree-view--tree-view"));
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test("should include a role of `tree`", async () => {
|
||||
await root.evaluate(node => {
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-view></fast-tree-view>
|
||||
`;
|
||||
|
@ -32,8 +16,14 @@ test.describe("TreeView", () => {
|
|||
await expect(element).toHaveAttribute("role", "tree");
|
||||
});
|
||||
|
||||
test("should set tree item `nested` properties to true if *any* tree item has nested items", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set tree item `nested` properties to true if *any* tree item has nested items", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-view");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-view>
|
||||
<fast-tree-item>
|
||||
|
@ -66,8 +56,14 @@ test.describe("TreeView", () => {
|
|||
).toBe(true);
|
||||
});
|
||||
|
||||
test("should set the selected state on tree items when a tree item is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should set the selected state on tree items when a tree item is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-view");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-view>
|
||||
<fast-tree-item>
|
||||
|
@ -98,8 +94,12 @@ test.describe("TreeView", () => {
|
|||
await expect(firstTreeItem).toHaveAttribute("aria-selected", "true");
|
||||
});
|
||||
|
||||
test("should only allow one tree item to be selected at a time", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should only allow one tree item to be selected at a time", async ({ page }) => {
|
||||
const element = page.locator("fast-tree-view");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-view>
|
||||
<fast-tree-item>
|
||||
|
@ -138,8 +138,14 @@ test.describe("TreeView", () => {
|
|||
}
|
||||
});
|
||||
|
||||
test("should toggle the expanded state when `expand-collapse-button` is clicked", async () => {
|
||||
await root.evaluate(node => {
|
||||
test("should toggle the expanded state when `expand-collapse-button` is clicked", async ({
|
||||
page,
|
||||
}) => {
|
||||
const element = page.locator("fast-tree-view");
|
||||
|
||||
await page.goto("http://localhost:6006");
|
||||
|
||||
await page.locator("#root").evaluate(node => {
|
||||
node.innerHTML = /* html */ `
|
||||
<fast-tree-view>
|
||||
<fast-tree-item>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg class="checked-indicator" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="m8.14 12.67 7.1-8.17 1.56 1.4-8.56 9.87-4.44-4.51 1.48-1.5 2.86 2.91Z"/></svg>
|
После Ширина: | Высота: | Размер: 213 B |
|
@ -0,0 +1,25 @@
|
|||
# FAST Foundation Test Harness
|
||||
|
||||
This directory contains the test harness for FAST Foundation, which is a static webpage hosted by a small express server. The page provides a way to run the FAST Foundation tests in a browser, by importing each component definition and registering it with the browser's custom element registry. This is the same method used by the FAST Foundation Storybook.
|
||||
|
||||
## Structure
|
||||
|
||||
```text
|
||||
test/
|
||||
├── public/ # static assets for the test harness
|
||||
│ ├── dist/ # gitignored build output directory
|
||||
│ │ └── bundle.js # generated test harness bundle
|
||||
│ └── index.html # test harness HTML file
|
||||
├── bundle.ts # entry point for the test harness bundle
|
||||
└── server.js # test harness express server
|
||||
```
|
||||
|
||||
## Building the test harness bundle
|
||||
|
||||
The bundle is built along with the main package bundles via the `build:rollup` script in `package.json`. The Rollup config outputs the bundle to `public/dist/bundle.js`.
|
||||
|
||||
## Running the test harness
|
||||
|
||||
The Playwright config uses its `webServer` property to specify the command to start the test harness. While Playwright is running, the test harness will be available at `http://localhost:6007`.
|
||||
|
||||
If you'd like to run the test harness manually, you can run `node test/server.js` from the `fast-foundation` directory. This will start the test harness server separately from Playwright, which can be useful for debugging.
|
|
@ -1,12 +1,13 @@
|
|||
import { useArgs } from "@storybook/client-api";
|
||||
import "@microsoft/fast-element";
|
||||
|
||||
import "../src/anchor/stories/anchor.register.js";
|
||||
import "../src/anchor/stories/anchor.stories.js";
|
||||
import "../src/anchored-region/stories/anchored-region.register.js";
|
||||
import "../src/avatar/stories/avatar.register.js";
|
||||
import "../src/badge/stories/badge.register.js";
|
||||
import "../src/button/stories/button.register.js";
|
||||
import "../src/card/stories/card.register.js";
|
||||
import "../src/checkbox/stories/checkbox.register.js";
|
||||
import "../src/design-token/stories/design-token.register.js";
|
||||
import "../src/dialog/stories/dialog.register.js";
|
||||
import "../src/disclosure/stories/disclosure.register.js";
|
||||
import "../src/divider/stories/divider.register.js";
|
||||
|
@ -59,13 +60,6 @@ import "../src/menu/stories/menu.register.js";
|
|||
import "../src/tree-item/stories/tree-item.register.js";
|
||||
import "../src/tree-view/stories/tree-view.register.js";
|
||||
|
||||
// Attach the FAST html helper to the global object so tests can use it
|
||||
import { FAST, html } from "@microsoft/fast-element";
|
||||
|
||||
FAST.html = html;
|
||||
|
||||
export const decorators = [
|
||||
(Story, context) => {
|
||||
const [_, updateArgs] = useArgs();
|
||||
return Story({ ...context, updateArgs });
|
||||
},
|
||||
];
|
||||
FAST["html"] = html;
|
|
@ -0,0 +1,152 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Test Harness</title>
|
||||
<style>
|
||||
:root {
|
||||
--accent-color: #da1a5f;
|
||||
--accent-fill-active: #df3c77;
|
||||
--accent-fill-focus: #dc2969;
|
||||
--accent-fill-hover: #da1a5f;
|
||||
--accent-fill-rest: #dc2969;
|
||||
--accent-foreground-active: #dc2969;
|
||||
--accent-foreground-focus: #da1a5f;
|
||||
--accent-foreground-hover: #b3154e;
|
||||
--accent-foreground-rest: #da1a5f;
|
||||
--ambient-shadow-alpha: calc(0.11 * (2 - var(--background-luminance, 1)));
|
||||
--ambient-shadow-color: rgba(0, 0, 0, var(--ambient-shadow-alpha));
|
||||
--ambient-shadow: 0 0 calc((var(--elevation) * 0.225px) + 2px)
|
||||
var(--ambient-shadow-color);
|
||||
--base-height-multiplier: 10;
|
||||
--base-horizontal-spacing-multiplier: 3;
|
||||
--base-layer-luminance: 1;
|
||||
--body-font: Arial, Helvetica, sans-serif;
|
||||
--clear-button-active: #ededed;
|
||||
--clear-button-hover: #f2f2f2;
|
||||
--control-corner-radius: 4;
|
||||
--density: 0;
|
||||
--design-unit: 4;
|
||||
--direction: ltr;
|
||||
--directional-shadow: 0 calc(var(--elevation) * 0.4px)
|
||||
calc((var(--elevation) * 0.9px)) var(--directional-shadow-color);
|
||||
--directional-shadow-alpha: calc(
|
||||
0.13 * (2 - var(--background-luminance, 1))
|
||||
);
|
||||
--directional-shadow-color: rgba(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
var(--directional-shadow-alpha)
|
||||
);
|
||||
--disabled-opacity: 0.3;
|
||||
--elevation: 14;
|
||||
--elevation-shadow: var(--ambient-shadow), var(--directional-shadow);
|
||||
--height-number: (var(--base-height-multiplier) + var(--density)) *
|
||||
var(--design-unit);
|
||||
--fill-color: #ffffff;
|
||||
--focus-stroke-inner: #ffffff;
|
||||
--focus-stroke-outer: #888888;
|
||||
--focus-stroke-width: 2;
|
||||
--foreground-on-accent-active-large: #000000;
|
||||
--foreground-on-accent-active: #000000;
|
||||
--foreground-on-accent-focus-large: #000000;
|
||||
--foreground-on-accent-focus: #ffffff;
|
||||
--foreground-on-accent-hover-large: #000000;
|
||||
--foreground-on-accent-hover: #ffffff;
|
||||
--foreground-on-accent-rest-large: #000000;
|
||||
--foreground-on-accent-rest: #ffffff;
|
||||
--neutral-color: #808080;
|
||||
--neutral-fill-active: #f2f2f2;
|
||||
--neutral-fill-focus: #ffffff;
|
||||
--neutral-fill-hover: #e5e5e5;
|
||||
--neutral-fill-input-active: #ffffff;
|
||||
--neutral-fill-input-focus: #ffffff;
|
||||
--neutral-fill-input-hover: #ffffff;
|
||||
--neutral-fill-input-rest: #ffffff;
|
||||
--neutral-fill-layer-rest: #f7f7f7;
|
||||
--neutral-fill-rest: #ededed;
|
||||
--neutral-fill-stealth-active: #f7f7f7;
|
||||
--neutral-fill-stealth-focus: #ffffff;
|
||||
--neutral-fill-stealth-hover: #f2f2f2;
|
||||
--neutral-fill-stealth-rest: #ffffff;
|
||||
--neutral-fill-strong-active: #838383;
|
||||
--neutral-fill-strong-focus: #767676;
|
||||
--neutral-fill-strong-hover: #616161;
|
||||
--neutral-fill-strong-rest: #767676;
|
||||
--neutral-foreground-hint: #767676;
|
||||
--neutral-foreground-rest: #2b2b2b;
|
||||
--neutral-layer-1: #ffffff;
|
||||
--neutral-layer-2: #e5e5e5;
|
||||
--neutral-layer-3: #dddddd;
|
||||
--neutral-layer-4: #d6d6d6;
|
||||
--neutral-layer-card-container: #f7f7f7;
|
||||
--neutral-layer-floating: #ffffff;
|
||||
--neutral-stroke-active: #d6d6d6;
|
||||
--neutral-stroke-divider-rest: #eaeaea;
|
||||
--neutral-stroke-focus: #bebebe;
|
||||
--neutral-stroke-hover: #979797;
|
||||
--neutral-stroke-rest: #bebebe;
|
||||
--stroke-width: 1;
|
||||
--tree-item-expand-collapse-hover: #e5e5e5;
|
||||
--tree-item-expand-collapse-selected-hover: #e0e0e0;
|
||||
--type-ramp-base-font-size: 14px;
|
||||
--type-ramp-base-line-height: 20px;
|
||||
--type-ramp-minus-1-font-size: 12px;
|
||||
--type-ramp-minus-1-line-height: 16px;
|
||||
--type-ramp-minus-2-font-size: 10px;
|
||||
--type-ramp-minus-2-line-height: 16px;
|
||||
--type-ramp-plus-1-font-size: 16px;
|
||||
--type-ramp-plus-1-line-height: 24px;
|
||||
--type-ramp-plus-2-font-size: 20px;
|
||||
--type-ramp-plus-2-line-height: 28px;
|
||||
--type-ramp-plus-3-font-size: 28px;
|
||||
--type-ramp-plus-3-line-height: 36px;
|
||||
--type-ramp-plus-4-font-size: 34px;
|
||||
--type-ramp-plus-4-line-height: 44px;
|
||||
--type-ramp-plus-5-font-size: 46px;
|
||||
--type-ramp-plus-5-line-height: 56px;
|
||||
--type-ramp-plus-6-font-size: 60px;
|
||||
--type-ramp-plus-6-line-height: 72px;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: var(--fill-color);
|
||||
color: var(--neutral-foreground-rest);
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<svg style="display: none">
|
||||
<symbol id="test-icon" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 5.5a1 1 0 100 2 1 1 0 000-2zm-5 1a1 1 0 112 0 1 1 0 01-2 0zm3.5-4a.5.5 0 00-1 0V3h-3C5.67 3 5 3.67 5 4.5v4c0 .83.67 1.5 1.5 1.5h7c.83 0 1.5-.67 1.5-1.5v-4c0-.83-.67-1.5-1.5-1.5h-3v-.5zM6.5 4h7c.28 0 .5.22.5.5v4a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-4c0-.28.22-.5.5-.5zm3.75 14c2.62-.04 4.2-.6 5.12-1.44A3.52 3.52 0 0016.5 14h.01v-.69c0-1-.81-1.8-1.8-1.8h-3.2v-.01H5.3c-.99 0-1.8.81-1.8 1.81v.7c.04.77.25 1.75 1.13 2.55.93.84 2.5 1.4 5.12 1.44h.5zm-4.94-5.5h9.38c.45 0 .81.37.81.81v.44c0 .69-.13 1.46-.8 2.07C14 16.45 12.66 17 10 17s-4.01-.55-4.7-1.18a2.63 2.63 0 01-.8-2.07v-.44c0-.44.36-.8.8-.8z"
|
||||
/>
|
||||
</symbol>
|
||||
<symbol
|
||||
id="test-icon-2"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.26 4.6a5.21 5.21 0 0 1 9.03 5.22l-.2.34a.5.5 0 0 1-.67.19l-3.47-2-1.93 3.38c1.34.4 2.5 1.33 3.31 2.52h-.09c-.34 0-.66.11-.92.31A4.9 4.9 0 0 0 9.5 12.5a4.9 4.9 0 0 0-3.82 2.06 1.5 1.5 0 0 0-1.01-.3 5.94 5.94 0 0 1 5.31-2.74l2.1-3.68-3.83-2.2a.5.5 0 0 1-.18-.7l.2-.33Zm.92.42 1.7.98.02-.02a8.08 8.08 0 0 1 3.27-2.74 4.22 4.22 0 0 0-4.99 1.78ZM14 7.8c.47-.82.7-1.46.77-2.09a5.8 5.8 0 0 0-.06-1.62 6.96 6.96 0 0 0-2.95 2.41L14 7.8Zm.87.5 1.61.93a4.22 4.22 0 0 0-.74-5.02c.07.56.09 1.1.02 1.63-.1.79-.38 1.56-.89 2.46Zm-9.63 7.3a.5.5 0 0 0-.96.03c-.17.7-.5 1.08-.86 1.3-.38.23-.87.32-1.42.32a.5.5 0 0 0 0 1c.64 0 1.33-.1 1.94-.47.34-.2.64-.5.88-.87a2.96 2.96 0 0 0 4.68-.01 2.96 2.96 0 0 0 4.74-.06c.64.9 1.7 1.41 2.76 1.41a.5.5 0 1 0 0-1c-.98 0-1.96-.64-2.29-1.65a.5.5 0 0 0-.95 0 1.98 1.98 0 0 1-3.79.07.5.5 0 0 0-.94 0 1.98 1.98 0 0 1-3.8-.08Z"
|
||||
/>
|
||||
</symbol>
|
||||
<symbol
|
||||
id="chevron-up-12-regular"
|
||||
viewBox="0 0 12 12"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2.15 7.35c.2.2.5.2.7 0L6 4.21l3.15 3.14a.5.5 0 1 0 .7-.7l-3.5-3.5a.5.5 0 0 0-.7 0l-3.5 3.5a.5.5 0 0 0 0 .7Z"
|
||||
/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<script src="dist/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
/* eslint-env node */
|
||||
import express from "express";
|
||||
|
||||
const PORT = process.env.PORT ?? 6007;
|
||||
|
||||
const app = express();
|
||||
|
||||
// host public folder
|
||||
app.use(express.static("test/public"));
|
||||
|
||||
// run server
|
||||
app.listen(PORT);
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declaration": false,
|
||||
"declarationDir": null,
|
||||
"outDir": "test/dist",
|
||||
"module": "ESNext"
|
||||
},
|
||||
"include": ["src/**/*.register.ts", "src/__test__/**/*.ts", "test/**/*.ts"]
|
||||
}
|
8452
yarn.lock
8452
yarn.lock
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче