-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Aligned repository structure with WDIO recommendation
- Loading branch information
Showing
9 changed files
with
184 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
serenity.project.name=serenity-js-mocha-webdriverio-template |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { contain, Ensure, equals, includes, isGreaterThan } from '@serenity-js/assertions' | ||
import { type Answerable, Check, d, type QuestionAdapter, Task, Wait } from '@serenity-js/core' | ||
import { By, Enter, ExecuteScript, isVisible, Key, Navigate, Page, PageElement, PageElements, Press, Text } from '@serenity-js/web' | ||
|
||
import { TodoListItem } from './TodoListItem' | ||
|
||
export class TodoList { | ||
|
||
// Public API captures the business domain-focused tasks | ||
// that an actor interacting with a TodoList app can perform | ||
|
||
static createEmptyList = () => | ||
Task.where('#actor creates an empty todo list', | ||
Navigate.to('https://todo-app.serenity-js.org/'), | ||
Ensure.that( | ||
Page.current().title().describedAs('website title'), | ||
equals('Serenity/JS TodoApp'), | ||
), | ||
Wait.until(this.newTodoInput(), isVisible()), | ||
TodoList.emptyLocalStorageIfNeeded(), | ||
) | ||
|
||
static emptyLocalStorageIfNeeded = () => | ||
Task.where('#actor empties local storage if needed', | ||
Check.whether(TodoList.persistedItems().length, isGreaterThan(0)) | ||
.andIfSo( | ||
TodoList.emptyLocalStorage(), | ||
Page.current().reload(), | ||
) | ||
) | ||
|
||
static createListContaining = (itemNames: Array<Answerable<string>>) => | ||
Task.where(`#actor starts with a list containing ${ itemNames.length } items`, | ||
TodoList.createEmptyList(), | ||
...itemNames.map(itemName => this.recordItem(itemName)) | ||
) | ||
|
||
static recordItem = (itemName: Answerable<string>) => | ||
Task.where(d `#actor records an item called ${ itemName }`, | ||
Enter.theValue(itemName).into(this.newTodoInput()), | ||
Press.the(Key.Enter).in(this.newTodoInput()), | ||
Wait.until(Text.ofAll(this.items()), contain(itemName)), | ||
) | ||
|
||
static markAsCompleted = (itemNames: Array<Answerable<string>>) => | ||
Task.where(d`#actor marks the following items as completed: ${ itemNames }`, | ||
...itemNames.map(itemName => TodoListItem.markAsCompleted(this.itemCalled(itemName))) | ||
) | ||
|
||
static markAsOutstanding = (itemNames: Array<Answerable<string>>) => | ||
Task.where(d`#actor marks the following items as outstanding: ${ itemNames }`, | ||
...itemNames.map(itemName => TodoListItem.markAsOutstanding(this.itemCalled(itemName))) | ||
) | ||
|
||
static outstandingItemsCount = () => | ||
Text.of(PageElement.located(By.tagName('strong')).of(this.outstandingItemsLabel())) | ||
.as(Number) | ||
.describedAs('number of items left') | ||
|
||
// Private API captures ways to locate interactive elements and data transformation logic. | ||
// Private API supports the public API and is not used in the test scenario directly. | ||
|
||
private static itemCalled = (name: Answerable<string>) => | ||
this.items() | ||
.where(Text, includes(name)) | ||
.first() | ||
.describedAs(d`an item called ${ name }`) | ||
|
||
private static outstandingItemsLabel = () => | ||
PageElement.located(By.css('.todo-count')) | ||
.describedAs('items left counter') | ||
|
||
private static newTodoInput = () => | ||
PageElement.located(By.css('.new-todo')) | ||
.describedAs('"What needs to be done?" input box') | ||
|
||
private static items = () => | ||
PageElements.located(By.css('.todo-list li')) | ||
.describedAs('displayed items') | ||
|
||
private static persistedItems = () => | ||
Page.current() | ||
.executeScript(` | ||
return window.localStorage['serenity-js-todo-app'] | ||
? JSON.parse(window.localStorage['serenity-js-todo-app']) | ||
: [] | ||
`).describedAs('persisted items') as QuestionAdapter<PersistedTodoItem[]> | ||
|
||
private static emptyLocalStorage = () => | ||
Task.where('#actor empties local storage', | ||
ExecuteScript.sync(`window.localStorage.removeItem('serenity-js-todo-app')`) | ||
) | ||
} | ||
|
||
interface PersistedTodoItem { | ||
id: number; | ||
name: string; | ||
completed: boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { contain, not } from '@serenity-js/assertions' | ||
import { Check, d, QuestionAdapter, Task } from '@serenity-js/core' | ||
import { By, Click, CssClasses, PageElement } from '@serenity-js/web' | ||
|
||
export class TodoListItem { | ||
|
||
// Public API captures the business domain-focused tasks | ||
// that an actor interacting with a TodoListItem app can perform | ||
|
||
static markAsCompleted = (item: QuestionAdapter<PageElement>) => | ||
Task.where(d `#actor marks ${ item } as completed`, | ||
Check.whether(CssClasses.of(item), not(contain('completed'))) | ||
.andIfSo(this.toggle(item)), | ||
) | ||
|
||
static markAsOutstanding = (item: QuestionAdapter<PageElement>) => | ||
Task.where(d `#actor marks ${ item } as outstanding`, | ||
Check.whether(CssClasses.of(item), contain('completed')) | ||
.andIfSo(this.toggle(item)), | ||
) | ||
|
||
static toggle = (item: QuestionAdapter<PageElement>) => | ||
Task.where(d `#actor toggles the completion status of ${ item }`, | ||
Click.on( | ||
TodoListItem.toggleButton().of(item), | ||
), | ||
) | ||
|
||
// Private API captures ways to locate interactive elements and data transformation logic. | ||
// Private API supports the public API and is not used in the test scenario directly. | ||
|
||
private static toggleButton = () => | ||
PageElement | ||
.located(By.css('input.toggle')) | ||
.describedAs('toggle button') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters