diff options
Diffstat (limited to 'e2e/lib')
-rw-r--r-- | e2e/lib/Console.ts | 68 | ||||
-rw-r--r-- | e2e/lib/FormOptionPage.ts | 177 | ||||
-rw-r--r-- | e2e/lib/JSONOptionPage.ts | 4 | ||||
-rw-r--r-- | e2e/lib/Page.ts | 4 |
4 files changed, 127 insertions, 126 deletions
diff --git a/e2e/lib/Console.ts b/e2e/lib/Console.ts index 2c128d1..4d017cc 100644 --- a/e2e/lib/Console.ts +++ b/e2e/lib/Console.ts @@ -1,7 +1,11 @@ import { WebDriver, By, Key } from "selenium-webdriver"; +export type CompletionGroups = { + title: string; + items: Array<CompletionItem>; +}; + export type CompletionItem = { - type: string; text: string; highlight: boolean; }; @@ -25,23 +29,17 @@ export class Console { } async execCommand(command: string): Promise<void> { - const input = await this.webdriver.findElement( - By.css("input.vimvixen-console-command-input") - ); + const input = await this.webdriver.findElement(By.css("input")); await input.sendKeys(command, Key.ENTER); } async getErrorMessage(): Promise<string> { - const p = await this.webdriver.findElement( - By.css(".vimvixen-console-error") - ); + const p = await this.webdriver.findElement(By.css("[role=alert]")); return p.getText(); } async getInformationMessage(): Promise<string> { - const p = await this.webdriver.findElement( - By.css(".vimvixen-console-info") - ); + const p = await this.webdriver.findElement(By.css("[role=status]")); return p.getText(); } @@ -50,36 +48,42 @@ export class Console { await input.sendKeys(...keys); } - getCompletions(): Promise<CompletionItem[]> { + getCompletions(): Promise<CompletionGroups[]> { return this.webdriver.executeScript(() => { - const items = document.querySelectorAll( - ".vimvixen-console-completion > li" - ); - if (items.length === 0) { + const groups = document.querySelectorAll("[role=group]"); + if (groups.length === 0) { throw new Error("completion items not found"); } - const objs = []; - for (const li of Array.from(items)) { - if (li.classList.contains("vimvixen-console-completion-title")) { - objs.push({ type: "title", text: li.textContent!.trim() }); - } else if (li.classList.contains("vimvixen-console-completion-item")) { - const highlight = li.classList.contains( - "vimvixen-completion-selected" - ); - objs.push({ type: "item", text: li.textContent!.trim(), highlight }); - } else { - throw new Error(`unexpected class: ${li.className}`); - } - } - return objs; + return Array.from(groups).map((group) => { + const describedby = group.getAttribute("aria-describedby") as string; + const title = document.getElementById(describedby)!; + const items = group.querySelectorAll("[role=menuitem]"); + + return { + title: title.textContent!.trim(), + items: Array.from(items).map((item) => ({ + text: document.getElementById( + item.getAttribute("aria-labelledby")! + )!.textContent, + highlight: item.getAttribute("aria-selected") === "true", + })), + }; + }); }); } async getTheme(): Promise<string> { - const wrapper = await this.webdriver.findElement(By.css("div[data-theme]")); - const theme = await wrapper.getAttribute("data-theme"); - return theme; + const color = (await this.webdriver.executeScript(() => { + const input = document.querySelector("input")!; + return window.getComputedStyle(input).backgroundColor; + })) as string; + if (color === "rgb(5, 32, 39)") { + return "dark"; + } else if (color === "rgb(255, 255, 255)") { + return "light"; + } + throw new Error(`unknown input color: ${color}`); } async close(): Promise<void> { diff --git a/e2e/lib/FormOptionPage.ts b/e2e/lib/FormOptionPage.ts index 5551684..666bac7 100644 --- a/e2e/lib/FormOptionPage.ts +++ b/e2e/lib/FormOptionPage.ts @@ -1,5 +1,5 @@ import { Lanthan } from "lanthan"; -import { WebDriver, By, until } from "selenium-webdriver"; +import { WebDriver, WebElement, By, error } from "selenium-webdriver"; export default class FormOptionPage { private webdriver: WebDriver; @@ -9,15 +9,15 @@ export default class FormOptionPage { } async setBlacklist(nth: number, url: string): Promise<void> { - const selector = ".form-blacklist-form-row > .column-url"; - const inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { + const fieldset = await this.getFieldsetByLegend("Blacklist"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + if (rows.length <= nth) { throw new RangeError("Index out of range to set a blacklist"); } - await inputs[nth].sendKeys(url); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); + + const input = rows[nth].findElement(By.css("[aria-label=URL]")); + await input.sendKeys(url); + await this.blurActiveElement(); } async setPartialBlacklist( @@ -25,121 +25,122 @@ export default class FormOptionPage { url: string, keys: string ): Promise<void> { - let selector = ".form-partial-blacklist-form-row > .column-url"; - let inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { + const fieldset = await this.getFieldsetByLegend("Partial blacklist"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + if (rows.length <= nth) { throw new RangeError("Index out of range to set a partial blacklist"); } - await inputs[nth].sendKeys(url); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); - selector = ".form-partial-blacklist-form-row > .column-keys"; - inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { - throw new RangeError("Index out of range to set a partial blacklist"); - } - await inputs[nth].sendKeys(keys); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); + const urlInput = rows[nth].findElement(By.css("[aria-label=URL]")); + await urlInput.sendKeys(url); + await this.blurActiveElement(); + + const keysInput = rows[nth].findElement(By.css("[aria-label=Keys]")); + await keysInput.sendKeys(keys); + await this.blurActiveElement(); } async setSearchEngine(nth: number, name: string, url: string) { - let selector = ".form-search-form-row > .column-name"; - let inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { + const fieldset = await this.getFieldsetByLegend("Search Engines"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + if (rows.length <= nth) { throw new RangeError("Index out of range to set a search engine"); } - await inputs[nth].sendKeys(name); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); - selector = ".form-search-form-row > .column-url"; - inputs = await this.webdriver.findElements(By.css(selector)); - if (inputs.length <= nth) { - throw new RangeError("Index out of range to set a search engine"); - } - await inputs[nth].sendKeys(url); - await this.webdriver.executeScript( - `document.querySelectorAll('${selector}')[${nth}].blur()` - ); + const nameInput = rows[nth].findElement(By.css("[aria-label=Name")); + await nameInput.sendKeys(name); + await this.blurActiveElement(); + + const urlInput = rows[nth].findElement(By.css("[aria-label=URL]")); + await urlInput.sendKeys(url); + await this.blurActiveElement(); } async addBlacklist(): Promise<void> { - const rows = await this.webdriver.findElements( - By.css(`.form-blacklist-form-row`) - ); - const button = await this.webdriver.findElement( - By.css(".form-blacklist-form .ui-add-button") - ); - await button.click(); - await this.webdriver.wait( - until.elementLocated( - By.css(`.form-blacklist-form-row:nth-child(${rows.length + 1})`) - ) - ); + const fieldset = await this.getFieldsetByLegend("Blacklist"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + const addButton = await fieldset.findElement(By.css("[aria-label=Add]")); + + await addButton.click(); + await this.webdriver.wait(async () => { + const newRows = await fieldset.findElements(By.css("[role=listitem]")); + return newRows.length == rows.length + 1; + }); } async addPartialBlacklist(): Promise<void> { - const rows = await this.webdriver.findElements( - By.css(`.form-partial-blacklist-form-row`) - ); - const button = await this.webdriver.findElement( - By.css(".form-partial-blacklist-form .ui-add-button") - ); - await button.click(); - await this.webdriver.wait( - until.elementLocated( - By.css(`.form-partial-blacklist-form-row:nth-child(${rows.length + 2})`) - ) - ); + const fieldset = await this.getFieldsetByLegend("Partial blacklist"); + const addButton = await fieldset.findElement(By.css("[aria-label=Add]")); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + + await addButton.click(); + await this.webdriver.wait(async () => { + const newRows = await fieldset.findElements(By.css("[role=listitem]")); + return newRows.length == rows.length + 1; + }); } async removeBlackList(nth: number): Promise<void> { - const buttons = await this.webdriver.findElements( - By.css(".form-blacklist-form-row .ui-delete-button") + const fieldset = await this.getFieldsetByLegend("Blacklist"); + const deleteButtons = await fieldset.findElements( + By.css("[aria-label=Delete]") ); - if (buttons.length <= nth) { + if (deleteButtons.length <= nth) { throw new RangeError("Index out of range to remove blacklist"); } - await buttons[nth].click(); + await deleteButtons[nth].click(); } async removePartialBlackList(nth: number): Promise<void> { - const buttons = await this.webdriver.findElements( - By.css(".form-partial-blacklist-form-row .ui-delete-button") - ); - if (buttons.length <= nth) { - throw new RangeError("Index out of range to remove partial blacklist"); + const fieldset = await this.getFieldsetByLegend("Partial blacklist"); + const deleteButtons = await fieldset.findElements( + By.css("[aria-label=Delete]") + ); + if (deleteButtons.length <= nth) { + throw new RangeError( + `Index out of range ${deleteButtons.length} to remove partial blacklist ${nth}` + ); } - await buttons[nth].click(); + await deleteButtons[nth].click(); } async addSearchEngine(): Promise<void> { - const rows = await this.webdriver.findElements( - By.css(`.form-search-form-row > .column-name`) - ); - const button = await this.webdriver.findElement( - By.css(".form-search-form > .ui-add-button") - ); - await button.click(); - await this.webdriver.wait( - until.elementLocated( - By.css(`.form-search-form-row:nth-child(${rows.length + 1})`) - ) - ); + const fieldset = await this.getFieldsetByLegend("Search Engines"); + const rows = await fieldset.findElements(By.css("[role=listitem]")); + const addButton = await fieldset.findElement(By.css("[aria-label=Add]")); + + await addButton.click(); + await this.webdriver.wait(async () => { + const newRows = await fieldset.findElements(By.css("[role=listitem]")); + return newRows.length == rows.length + 1; + }); } async setDefaultSearchEngine(nth: number): Promise<void> { - const radios = await this.webdriver.findElements( - By.css(".form-search-form-row input[type=radio]") + const fieldset = await this.getFieldsetByLegend("Search Engines"); + const radios = await fieldset.findElements( + By.css("[name=default][type=radio]") ); if (radios.length <= nth) { throw new RangeError("Index out of range to set a default search engine"); } await radios[nth].click(); } + + private async getFieldsetByLegend(legendText: string): Promise<WebElement> { + const fieldsets = await this.webdriver.findElements(By.tagName("fieldset")); + for (const fieldset of fieldsets) { + const legend = await fieldset.findElement(By.tagName("legend")); + if ((await legend.getText()) === legendText) { + return fieldset; + } + } + throw new error.NoSuchElementError( + `Unable to locate fieldset with legend: ` + legendText + ); + } + + private async blurActiveElement(): Promise<void> { + await this.webdriver.executeScript(`document.activeElement.blur()`); + } } diff --git a/e2e/lib/JSONOptionPage.ts b/e2e/lib/JSONOptionPage.ts index 0f2b0a7..2d8147e 100644 --- a/e2e/lib/JSONOptionPage.ts +++ b/e2e/lib/JSONOptionPage.ts @@ -20,9 +20,7 @@ export default class JSONOptionPage { } async getErrorMessage(): Promise<string> { - const error = await this.webdriver.findElement( - By.css(".settings-ui-input-error") - ); + const error = await this.webdriver.findElement(By.css("p[role=alert]")); return error.getText(); } } diff --git a/e2e/lib/Page.ts b/e2e/lib/Page.ts index 85bda8d..6531f19 100644 --- a/e2e/lib/Page.ts +++ b/e2e/lib/Page.ts @@ -46,9 +46,7 @@ export default class Page { await this.sendKeys(":"); await this.webdriver.wait(until.elementIsVisible(iframe)); await this.webdriver.switchTo().frame(0); - await this.webdriver.wait( - until.elementLocated(By.css("input.vimvixen-console-command-input")) - ); + await this.webdriver.wait(until.elementLocated(By.css("input"))); return new Console(this.webdriver); } |