Skip to content

Commit b834d85

Browse files
authored
Merge pull request #659 from thefrontside/typedoc-poc
Start adding docs via typedoc
2 parents bf88b44 + a1c4df8 commit b834d85

33 files changed

+996
-101
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules
22
yarn-error.log
33
/packages/*/dist
4+
/packages/*/docs

packages/bigtest/API.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# BigTest
2+
3+
This is cool stuff {@link createInteractor}, yeah!

packages/bigtest/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@frontside/typescript": "^1.1.0",
2424
"@types/node": "^13.13.4",
2525
"ts-node": "*",
26+
"typedoc": "^0.20.0-beta.8",
2627
"typescript": "3.9.7"
2728
},
2829
"dependencies": {

packages/bigtest/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from '@bigtest/interactor';
2-
export * from '@bigtest/suite';
2+
export { test, TestBuilder } from '@bigtest/suite';

packages/bigtest/typedoc.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"out": "docs",
3+
"name": "BigTest",
4+
"entryPoints": "src/index.ts",
5+
"readme": "API.md",
6+
"includeVersion": true
7+
}

packages/interactor/API.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Interactors
2+
3+
## Built in interactors
4+
5+
We provide a set of interactors built in.
6+
7+
## Custom interactors
8+
9+
You can create your own interactors with {@link createInteractor}.

packages/interactor/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
"express": "^4.17.1",
4343
"jsdom": "^16.2.2",
4444
"mocha": "^6.2.2",
45+
"typedoc": "^0.20.0-beta.8",
46+
"typescript": "3.9.7",
4547
"ts-node": "*",
4648
"wait-on": "^5.2.0"
4749
},

packages/interactor/src/app.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { Interaction } from './interaction';
22
import { Page } from './page';
33

4+
/**
5+
* @hidden
6+
*/
47
export const App = {
58
visit(path = '/'): Interaction<void> {
69
console.warn('App.visit is deprecated, please use Page.visit instead');

packages/interactor/src/create-interactor.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
11
import { bigtestGlobals } from '@bigtest/globals';
2-
import { InteractorSpecification, FilterParams, Filters, Actions, InteractorInstance, LocatorFn } from './specification';
2+
import { InteractorSpecification, InteractorBuilder, InteractorConstructor, FilterParams, Filters, Actions, InteractorInstance, LocatorFn } from './specification';
33
import { Locator } from './locator';
44
import { Filter } from './filter';
55
import { Interactor } from './interactor';
66
import { interaction } from './interaction';
77

88
const defaultLocator: LocatorFn<Element> = (element) => element.textContent || "";
99

10-
export function createInteractor<E extends Element>(interactorName: string) {
11-
return function<F extends Filters<E> = {}, A extends Actions<E> = {}>(specification: InteractorSpecification<E, F, A>) {
10+
11+
/**
12+
* Create a custom interactor. Due to TypeScript inference issues, this creates an
13+
* {@link InteractorBuilder}, which you will need to create the actual
14+
* interactor. See {@link InteractorSpecification} for detailed breakdown of
15+
* available options for the builder.
16+
*
17+
* ### Creating a simple interactor
18+
*
19+
* ``` typescript
20+
* let Paragraph = createInteractor('paragraph')({ selector: 'p' });
21+
* ```
22+
*
23+
* Note the double function call!
24+
*
25+
* @param interactorName The human readable name of the interactor, used mainly for debugging purposes and error messages
26+
* @typeParam E The type of DOM Element that this interactor operates on. By specifying the element type, actions and filters defined for the interactor can be type checked against the actual element type.
27+
* @returns You will need to call the returned builder to create an interactor.
28+
*/
29+
export function createInteractor<E extends Element>(interactorName: string): InteractorBuilder<E> {
30+
return function<F extends Filters<E> = {}, A extends Actions<E> = {}>(specification: InteractorSpecification<E, F, A>): InteractorConstructor<E, F, A> {
1231
let InteractorClass = class extends Interactor<E, F, A> {};
1332

1433
for(let [actionName, action] of Object.entries(specification.actions || {})) {

packages/interactor/src/definitions/button.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ function isButtonElement(element: HTMLInputElement | HTMLButtonElement): element
55
return element.tagName === 'BUTTON';
66
}
77

8-
export const Button = createInteractor<HTMLInputElement | HTMLButtonElement>('button')({
8+
const ButtonInteractor = createInteractor<HTMLInputElement | HTMLButtonElement>('button')({
99
selector: 'button,input[type=button],input[type=submit],input[type=reset],input[type=image]',
1010
locator(element) {
1111
if(isButtonElement(element)) {
@@ -32,3 +32,36 @@ export const Button = createInteractor<HTMLInputElement | HTMLButtonElement>('bu
3232
blur: perform((element) => { element.blur(); }),
3333
},
3434
});
35+
36+
/**
37+
* Call this {@link InteractorConstructor} to initialize a button {@link Interactor}.
38+
* The button interactor can be used to interact with buttons on the page and
39+
* to assert on their state.
40+
*
41+
* The button is located by the visible text on the button.
42+
*
43+
* ### Example
44+
*
45+
* ``` typescript
46+
* await Button('Submit').click();
47+
* await Button('Submit').is({ disabled: true });
48+
* await Button({ id: 'submit-button', disabled: true }).exists();
49+
* ```
50+
*
51+
* ### Filters
52+
*
53+
* - `title`: *string* – Filter by title
54+
* - `id`: *string* – Filter by id
55+
* - `visible`: *boolean* – Filter by visibility. Defaults to `true`. See {@link isVisible}.
56+
* - `disabled`: *boolean* – Filter by whether the button is disabled. Defaults to `false`.
57+
* - `focused`: *boolean* – Filter by whether the button is focused. See {@link focused}.
58+
*
59+
* ### Actions
60+
*
61+
* - `click()`: *{@link Interaction}* – Click on the button
62+
* - `focus()`: *{@link Interaction}* – Move focus to the button
63+
* - `blur()`: *{@link Interaction}* – Move focus away from the button
64+
*
65+
* @category Interactor
66+
*/
67+
export const Button = ButtonInteractor;

packages/interactor/src/definitions/check-box.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createInteractor, perform, focused } from '../index';
22
import { isVisible } from 'element-is-visible';
33

4-
export const CheckBox = createInteractor<HTMLInputElement>('check box')({
4+
const CheckBoxInteractor = createInteractor<HTMLInputElement>('check box')({
55
selector: 'input[type=checkbox]',
66
locator: (element) => element.labels ? (Array.from(element.labels)[0]?.textContent || '') : '',
77
filters: {
@@ -26,3 +26,39 @@ export const CheckBox = createInteractor<HTMLInputElement>('check box')({
2626
toggle: perform((element) => { element.click(); }),
2727
},
2828
});
29+
30+
/**
31+
* Call this {@link InteractorConstructor} to initialize a checkbox {@link Interactor}.
32+
* The checkbox interactor can be used to interact with checkboxes on the page and
33+
* to assert on their state.
34+
*
35+
* The checkbox is located by the text of its label.
36+
*
37+
* ### Example
38+
*
39+
* ``` typescript
40+
* await CheckBox('Submit').click();
41+
* await CheckBox('Submit').is({ disabled: true });
42+
* await CheckBox({ id: 'submit-button', disabled: true }).exists();
43+
* ```
44+
*
45+
* ### Filters
46+
*
47+
* - `title`: *string* – Filter by title
48+
* - `id`: *string* – Filter by id
49+
* - `visible`: *boolean* – Filter by visibility. Defaults to `true`. See {@link isVisible}.
50+
* - `valid`: *boolean* – Filter by whether the checkbox is valid.
51+
* - `checked`: *boolean* – Filter by whether the checkbox is checked.
52+
* - `disabled`: *boolean* – Filter by whether the checkbox is disabled. Defaults to `false`.
53+
* - `focused`: *boolean* – Filter by whether the checkbox is focused. See {@link focused}.
54+
*
55+
* ### Actions
56+
*
57+
* - `click()`: *{@link Interaction}* – Click on the checkbox
58+
* - `check()`: *{@link Interaction}* – Check the checkbox if it is not checked
59+
* - `uncheck()`: *{@link Interaction}* – Uncheck the checkbox if it is checked
60+
* - `toggle()`: *{@link Interaction}* – Toggle the checkbox
61+
*
62+
* @category Interactor
63+
*/
64+
export const CheckBox = CheckBoxInteractor;
Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
import { createInteractor } from '../create-interactor';
22
import { isVisible } from 'element-is-visible';
33

4-
export const Heading = createInteractor<HTMLHeadingElement>('heading')({
4+
const HeadingInteractor = createInteractor<HTMLHeadingElement>('heading')({
55
selector: 'h1,h2,h3,h4,h5,h6',
66
filters: {
77
level: (element) => parseInt(element.tagName[1]),
88
visible: { apply: isVisible, default: true },
99
}
1010
});
11+
12+
/**
13+
* Call this {@link InteractorConstructor} to initialize a heading {@link Interactor}.
14+
* The heading interactor can be used to assert on the state of headings on the page,
15+
* represented by the `h1` through `h6` tags.
16+
*
17+
* ### Example
18+
*
19+
* ``` typescript
20+
* await Heading('Welcome!').exists();
21+
* ```
22+
*
23+
* ### Filters
24+
*
25+
* - `level`: *number* – The level of the heading, for example, the level of `h3` is `3`.
26+
* - `visible`: *boolean* – Filter by visibility. Defaults to `true`. See {@link isVisible}.
27+
*
28+
* @category Interactor
29+
*/
30+
export const Heading = HeadingInteractor;

packages/interactor/src/definitions/link.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createInteractor, perform, focused } from '../index';
22
import { isVisible } from 'element-is-visible';
33

4-
export const Link = createInteractor<HTMLLinkElement>('link')({
4+
const LinkInteractor = createInteractor<HTMLLinkElement>('link')({
55
selector: 'a[href]',
66
filters: {
77
title: (element) => element.title,
@@ -14,3 +14,34 @@ export const Link = createInteractor<HTMLLinkElement>('link')({
1414
click: perform((element) => { element.click(); })
1515
},
1616
});
17+
18+
/**
19+
* Call this {@link InteractorConstructor} to initialize a link {@link Interactor}.
20+
* The link interactor can be used to interact with links on the page and
21+
* to assert on their state.
22+
*
23+
* The link is located by its text.
24+
*
25+
* ### Example
26+
*
27+
* ``` typescript
28+
* await Link('Home').click();
29+
* await Link('Home').has({ href: '/' });
30+
* await Link({ id: 'home-link', href: '/' }).exists();
31+
* ```
32+
*
33+
* ### Filters
34+
*
35+
* - `title`: *string* – Filter by title
36+
* - `id`: *string* – Filter by id
37+
* - `href`: *string* – The value of the href attribute that the link points to
38+
* - `visible`: *boolean* – Filter by visibility. Defaults to `true`. See {@link isVisible}.
39+
* - `focused`: *boolean* – Filter by whether the link is focused. See {@link focused}.
40+
*
41+
* ### Actions
42+
*
43+
* - `click()`: *{@link Interaction}* – Click on the link
44+
*
45+
* @category Interactor
46+
*/
47+
export const Link = LinkInteractor;

packages/interactor/src/definitions/multi-select.ts

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { createInteractor, perform } from '../index';
1+
import { createInteractor, perform, focused } from '../index';
22
import { isVisible } from 'element-is-visible';
33
import { dispatchChange, dispatchInput } from '../dispatch';
44
import { getSelect } from '../get-select';
55

6-
const SelectOption = createInteractor<HTMLOptionElement>('option')({
6+
const MultiSelectOption = createInteractor<HTMLOptionElement>('option')({
77
selector: 'option',
88
locator: (element) => element.label,
99
filters: {
@@ -43,35 +43,75 @@ const SelectOption = createInteractor<HTMLOptionElement>('option')({
4343
},
4444
});
4545

46-
export const MultiSelect = createInteractor<HTMLSelectElement>('select box')({
46+
const MultiSelectInteractor = createInteractor<HTMLSelectElement>('select box')({
4747
selector: 'select[multiple]',
4848
locator: (element) => element.labels ? (Array.from(element.labels)[0]?.textContent || '') : '',
4949
filters: {
5050
title: (element) => element.title,
5151
id: (element) => element.id,
5252
valid: (element) => element.validity.valid,
5353
values: (element) => Array.from(element.selectedOptions).map((o) => o.label),
54-
visible: {
55-
apply: (element) => isVisible(element) || (element.labels && Array.from(element.labels).some(isVisible)),
56-
default: true
57-
},
54+
visible: { apply: isVisible, default: true },
5855
disabled: {
5956
apply: (element) => element.disabled,
6057
default: false
61-
}
58+
},
59+
focused
6260
},
6361
actions: {
6462
click: perform((element) => { element.click(); }),
6563
focus: perform((element) => { element.focus(); }),
6664
blur: perform((element) => { element.blur(); }),
67-
choose: async (interactor, value: string) => {
68-
await interactor.find(SelectOption(value)).choose();
65+
choose: async (interactor, text: string) => {
66+
await interactor.find(MultiSelectOption(text)).choose();
6967
},
70-
select: async (interactor, value: string) => {
71-
await interactor.find(SelectOption(value)).select();
68+
select: async (interactor, text: string) => {
69+
await interactor.find(MultiSelectOption(text)).select();
7270
},
73-
deselect: async (interactor, value: string) => {
74-
await interactor.find(SelectOption(value)).deselect();
71+
deselect: async (interactor, text: string) => {
72+
await interactor.find(MultiSelectOption(text)).deselect();
7573
},
7674
},
7775
});
76+
77+
/**
78+
* Call this {@link InteractorConstructor} to initialize an {@link Interactor}
79+
* for select boxes with multiple select. The multi select interactor can be
80+
* used to interact with select boxes with the `multiple` attribute and to
81+
* assert on their state.
82+
*
83+
* See {@link Select} for an interactor for single select boxes.
84+
*
85+
* The multi select is located by the text of its label.
86+
*
87+
* ### Example
88+
*
89+
* ``` typescript
90+
* await MultiSelect('Language').select('English');
91+
* await MultiSelect('Language').select('German');
92+
* await MultiSelect('Language').deselect('Swedish');
93+
* await MultiSelect('Language').has({ values: ['English', 'German'] });
94+
* ```
95+
*
96+
* ### Filters
97+
*
98+
* - `title`: *string* – Filter by title
99+
* - `id`: *string* – Filter by id
100+
* - `valid`: *boolean* – Filter by whether the checkbox is valid.
101+
* - `values`: *string[]* – Filter by the text of the selected options.
102+
* - `visible`: *boolean* – Filter by visibility. Defaults to `true`. See {@link isVisible}.
103+
* - `disabled`: *boolean* – Filter by whether the checkbox is disabled. Defaults to `false`.
104+
* - `focused`: *boolean* – Filter by whether the checkbox is focused. See {@link focused}.
105+
*
106+
* ### Actions
107+
*
108+
* - `click()`: *{@link Interaction}* – Click on the multi select
109+
* - `focus()`: *{@link Interaction}* – Move focus to the multi select
110+
* - `blur()`: *{@link Interaction}* – Move focus away from the multi select
111+
* - `choose(text: string)`: *{@link Interaction}* – Choose the option with the given text from the multi select. Will deselect all other selected options.
112+
* - `select(text: string)`: *{@link Interaction}* – Add the option with the given text to the selection.
113+
* - `deselect(text: string)`: *{@link Interaction}* – Remove the option with the given text from the selection.
114+
*
115+
* @category Interactor
116+
*/
117+
export const MultiSelect = MultiSelectInteractor;

0 commit comments

Comments
 (0)