diff options
| author | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-05-02 17:25:56 +0900 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-02 17:25:56 +0900 | 
| commit | 5df0537bcf65a341e79852b1b30379c73318529c (patch) | |
| tree | aee5efe52412855f620cb514a13a2c14373f27b7 /e2e/lib | |
| parent | 685f2b7b69218b06b5bb676069e35f79c5048c9b (diff) | |
| parent | 75abd90ecb8201ad845b266f96220d8adfe19b2d (diff) | |
Merge pull request #749 from ueokande/qa-0.28
QA 0.28
Diffstat (limited to 'e2e/lib')
| -rw-r--r-- | e2e/lib/Console.ts | 49 | ||||
| -rw-r--r-- | e2e/lib/FormOptionPage.ts | 114 | ||||
| -rw-r--r-- | e2e/lib/JSONOptionPage.ts | 20 | ||||
| -rw-r--r-- | e2e/lib/OptionPage.ts | 16 | ||||
| -rw-r--r-- | e2e/lib/Page.ts | 63 | ||||
| -rw-r--r-- | e2e/lib/SettingRepository.ts | 13 | ||||
| -rw-r--r-- | e2e/lib/TestServer.ts | 31 | ||||
| -rw-r--r-- | e2e/lib/clipboard.ts | 73 | 
8 files changed, 226 insertions, 153 deletions
| diff --git a/e2e/lib/Console.ts b/e2e/lib/Console.ts index e3bd2d6..68c0e10 100644 --- a/e2e/lib/Console.ts +++ b/e2e/lib/Console.ts @@ -1,64 +1,73 @@ -import { WebDriver, By, Key } from 'selenium-webdriver'; +import { WebDriver, By, Key } from "selenium-webdriver";  export type CompletionItem = {    type: string;    text: string;    highlight: boolean; -} +};  export class Console { -  constructor(private webdriver: WebDriver) { -  } +  constructor(private webdriver: WebDriver) {}    async sendKeys(...keys: string[]) { -    const input = await this.webdriver.findElement(By.css('input')); +    const input = await this.webdriver.findElement(By.css("input"));      input.sendKeys(...keys);    }    async currentValue() {      return await this.webdriver.executeScript(() => { -      const input = document.querySelector('input'); +      const input = document.querySelector("input");        if (input === null) { -        throw new Error('could not find input element'); +        throw new Error("could not find input element");        }        return input.value;      });    }    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.vimvixen-console-command-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(".vimvixen-console-error") +    );      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(".vimvixen-console-info") +    );      return p.getText();    }    async inputKeys(...keys: string[]) { -    const input = await this.webdriver.findElement(By.css('input')); +    const input = await this.webdriver.findElement(By.css("input"));      await input.sendKeys(...keys);    }    getCompletions(): Promise<CompletionItem[]> {      return this.webdriver.executeScript(() => { -      const items = document.querySelectorAll('.vimvixen-console-completion > li'); +      const items = document.querySelectorAll( +        ".vimvixen-console-completion > li" +      );        if (items.length === 0) { -        throw new Error('completion items not found'); +        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 ('vimvixen-console-completion-item') { -          const highlight = li.classList.contains('vimvixen-completion-selected'); -          objs.push({ type: 'item', text: li.textContent!!.trim(), highlight }); +        if (li.classList.contains("vimvixen-console-completion-title")) { +          objs.push({ type: "title", text: li.textContent!!.trim() }); +        } else if ("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}`);          } @@ -68,10 +77,10 @@ export class Console {    }    async close(): Promise<void> { -    const input = await this.webdriver.findElement(By.css('input')); +    const input = await this.webdriver.findElement(By.css("input"));      await input.sendKeys(Key.ESCAPE);      // TODO remove sleep -    await new Promise(resolve => setTimeout(resolve, 100)); +    await new Promise((resolve) => setTimeout(resolve, 100));      await (this.webdriver.switchTo() as any).parentFrame();    }  } diff --git a/e2e/lib/FormOptionPage.ts b/e2e/lib/FormOptionPage.ts index 33ce2a7..5551684 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 { Lanthan } from "lanthan"; +import { WebDriver, By, until } from "selenium-webdriver";  export default class FormOptionPage {    private webdriver: WebDriver; @@ -9,92 +9,136 @@ export default class FormOptionPage {    }    async setBlacklist(nth: number, url: string): Promise<void> { -    const selector = '.form-blacklist-form-row > .column-url'; +    const selector = ".form-blacklist-form-row > .column-url";      const inputs = await this.webdriver.findElements(By.css(selector));      if (inputs.length <= nth) { -      throw new RangeError('Index out of range to set a blacklist') +      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()`); +    await this.webdriver.executeScript( +      `document.querySelectorAll('${selector}')[${nth}].blur()` +    );    } -  async setPartialBlacklist(nth: number, url: string, keys: string): Promise<void> { -    let selector = '.form-partial-blacklist-form-row > .column-url'; +  async setPartialBlacklist( +    nth: number, +    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) { -      throw new RangeError('Index out of range to set a partial blacklist') +      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()`); +    await this.webdriver.executeScript( +      `document.querySelectorAll('${selector}')[${nth}].blur()` +    ); -    selector = '.form-partial-blacklist-form-row > .column-keys'; +    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') +      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()`); +    await this.webdriver.executeScript( +      `document.querySelectorAll('${selector}')[${nth}].blur()` +    );    }    async setSearchEngine(nth: number, name: string, url: string) { -    let selector = '.form-search-form-row > .column-name'; +    let selector = ".form-search-form-row > .column-name";      let inputs = await this.webdriver.findElements(By.css(selector));      if (inputs.length <= nth) { -      throw new RangeError('Index out of range to set a search engine') +      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()`); +    await this.webdriver.executeScript( +      `document.querySelectorAll('${selector}')[${nth}].blur()` +    ); -    selector = '.form-search-form-row > .column-url'; +    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') +      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()`); +    await this.webdriver.executeScript( +      `document.querySelectorAll('${selector}')[${nth}].blur()` +    );    }    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')) +    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})`))); +    await this.webdriver.wait( +      until.elementLocated( +        By.css(`.form-blacklist-form-row:nth-child(${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')) +    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})`))); +    await this.webdriver.wait( +      until.elementLocated( +        By.css(`.form-partial-blacklist-form-row:nth-child(${rows.length + 2})`) +      ) +    );    }    async removeBlackList(nth: number): Promise<void> { -    const buttons = await this.webdriver.findElements(By.css('.form-blacklist-form-row .ui-delete-button')); +    const buttons = await this.webdriver.findElements( +      By.css(".form-blacklist-form-row .ui-delete-button") +    );      if (buttons.length <= nth) { -      throw new RangeError('Index out of range to remove blacklist') +      throw new RangeError("Index out of range to remove blacklist");      } -    await buttons[nth].click() +    await buttons[nth].click();    }    async removePartialBlackList(nth: number): Promise<void> { -    const buttons = await this.webdriver.findElements(By.css('.form-partial-blacklist-form-row .ui-delete-button')); +    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') +      throw new RangeError("Index out of range to remove partial blacklist");      } -    await buttons[nth].click() +    await buttons[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')) +    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})`))); +    await this.webdriver.wait( +      until.elementLocated( +        By.css(`.form-search-form-row:nth-child(${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 radios = await this.webdriver.findElements( +      By.css(".form-search-form-row input[type=radio]") +    );      if (radios.length <= nth) { -      throw new RangeError('Index out of range to set a default search engine'); +      throw new RangeError("Index out of range to set a default search engine");      }      await radios[nth].click();    } diff --git a/e2e/lib/JSONOptionPage.ts b/e2e/lib/JSONOptionPage.ts index d6ed7ee..1c2db5b 100644 --- a/e2e/lib/JSONOptionPage.ts +++ b/e2e/lib/JSONOptionPage.ts @@ -1,5 +1,5 @@ -import { Lanthan } from 'lanthan'; -import { WebDriver, By } from 'selenium-webdriver'; +import { Lanthan } from "lanthan"; +import { WebDriver, By } from "selenium-webdriver";  export default class JSONOptionPage {    private webdriver: WebDriver; @@ -9,14 +9,20 @@ export default class JSONOptionPage {    }    async updateSettings(value: string): Promise<void> { -    const textarea = await this.webdriver.findElement(By.css('textarea')); -    await this.webdriver.executeScript(`document.querySelector('textarea').value = '${value}'`) -    await textarea.sendKeys(' '); -    await this.webdriver.executeScript(() => document.querySelector('textarea')!!.blur()); +    const textarea = await this.webdriver.findElement(By.css("textarea")); +    await this.webdriver.executeScript( +      `document.querySelector('textarea').value = '${value}'` +    ); +    await textarea.sendKeys(" "); +    await this.webdriver.executeScript(() => +      document.querySelector("textarea")!!.blur() +    );    }    async getErrorMessage(): Promise<string> { -    const error = await this.webdriver.findElement(By.css('.settings-ui-input-error')); +    const error = await this.webdriver.findElement( +      By.css(".settings-ui-input-error") +    );      return error.getText();    }  } diff --git a/e2e/lib/OptionPage.ts b/e2e/lib/OptionPage.ts index 9f994a0..e1ea759 100644 --- a/e2e/lib/OptionPage.ts +++ b/e2e/lib/OptionPage.ts @@ -1,7 +1,7 @@ -import { Lanthan } from 'lanthan'; -import { WebDriver, By } from 'selenium-webdriver'; -import JSONOptionPage from './JSONOptionPage'; -import FormOptionPage from './FormOptionPage'; +import { Lanthan } from "lanthan"; +import { WebDriver, By } from "selenium-webdriver"; +import JSONOptionPage from "./JSONOptionPage"; +import FormOptionPage from "./FormOptionPage";  export default class OptionPage {    private webdriver: WebDriver; @@ -11,13 +11,17 @@ export default class OptionPage {    }    static async open(lanthan: Lanthan) { -    const url = await lanthan.getWebExtBrowser().runtime.getURL("build/settings.html") +    const url = await lanthan +      .getWebExtBrowser() +      .runtime.getURL("build/settings.html");      await lanthan.getWebDriver().navigate().to(url);      return new OptionPage(lanthan);    }    async switchToForm(): Promise<FormOptionPage> { -    const useFormInput = await this.webdriver.findElement(By.css('#setting-source-form')); +    const useFormInput = await this.webdriver.findElement( +      By.css("#setting-source-form") +    );      await useFormInput.click();      await this.webdriver.switchTo().alert().accept();      return new FormOptionPage(this.lanthan); diff --git a/e2e/lib/Page.ts b/e2e/lib/Page.ts index 31605cb..85bda8d 100644 --- a/e2e/lib/Page.ts +++ b/e2e/lib/Page.ts @@ -1,19 +1,18 @@ -import { WebDriver, By, until } from 'selenium-webdriver'; -import { Console } from './Console'; +import { WebDriver, By, until } from "selenium-webdriver"; +import { Console } from "./Console";  type Hint = { -  displayed: boolean, -  text: string, +  displayed: boolean; +  text: string;  };  type Selection = { -  from: number, -  to: number, +  from: number; +  to: number;  };  export default class Page { -  private constructor(private webdriver: WebDriver) { -  } +  private constructor(private webdriver: WebDriver) {}    static async currentContext(webdriver: WebDriver): Promise<Page> {      await Page.waitForConsoleLoaded(webdriver); @@ -26,8 +25,10 @@ export default class Page {      return new Page(webdriver);    } -  async sendKeys(...keys: Array<string|number|Promise<string|number>>): Promise<void> { -    const body = await this.webdriver.findElement(By.css('body')); +  async sendKeys( +    ...keys: Array<string | number | Promise<string | number>> +  ): Promise<void> { +    const body = await this.webdriver.findElement(By.css("body"));      await body.sendKeys(...keys);    } @@ -38,17 +39,23 @@ export default class Page {    }    async showConsole(): Promise<Console> { -    const iframe = this.webdriver.findElement(By.css('#vimvixen-console-frame')); +    const iframe = this.webdriver.findElement( +      By.css("#vimvixen-console-frame") +    ); -    await this.sendKeys(':'); +    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.vimvixen-console-command-input")) +    );      return new Console(this.webdriver);    }    async getConsole(): Promise<Console> { -    const iframe = this.webdriver.findElement(By.css('#vimvixen-console-frame')); +    const iframe = this.webdriver.findElement( +      By.css("#vimvixen-console-frame") +    );      await this.webdriver.wait(until.elementIsVisible(iframe));      await this.webdriver.switchTo().frame(0); @@ -68,16 +75,22 @@ export default class Page {    }    pageHeight(): Promise<number> { -    return this.webdriver.executeScript(() => window.document.documentElement.clientHeight); +    return this.webdriver.executeScript( +      () => window.document.documentElement.clientHeight +    );    }    async getSelection(): Promise<Selection> { -    const obj = await this.webdriver.executeScript(`return window.getSelection();`) as any; +    const obj = (await this.webdriver.executeScript( +      `return window.getSelection();` +    )) as any;      return { from: obj.anchorOffset, to: obj.focusOffset };    }    async clearSelection(): Promise<void> { -    await this.webdriver.executeScript(`window.getSelection().removeAllRanges()`); +    await this.webdriver.executeScript( +      `window.getSelection().removeAllRanges()` +    );    }    async switchToTop(): Promise<void> { @@ -85,15 +98,17 @@ export default class Page {    }    async waitAndGetHints(): Promise<Hint[]> { -    await this.webdriver.wait(until.elementsLocated(By.css('.vimvixen-hint'))); +    await this.webdriver.wait(until.elementsLocated(By.css(".vimvixen-hint"))); -    const elements = await this.webdriver.findElements(By.css(`.vimvixen-hint`)); +    const elements = await this.webdriver.findElements( +      By.css(`.vimvixen-hint`) +    );      const hints = [];      for (const e of elements) { -      const display = await e.getCssValue('display'); +      const display = await e.getCssValue("display");        const text = await e.getText();        hints.push({ -        displayed: display !== 'none', +        displayed: display !== "none",          text: text,        });      } @@ -105,7 +120,9 @@ export default class Page {      if (!topFrame) {        return;      } -    await webdriver.wait(until.elementLocated(By.css('iframe.vimvixen-console-frame'))); -    await new Promise(resolve => setTimeout(resolve, 100)); +    await webdriver.wait( +      until.elementLocated(By.css("iframe.vimvixen-console-frame")) +    ); +    await new Promise((resolve) => setTimeout(resolve, 100));    }  } diff --git a/e2e/lib/SettingRepository.ts b/e2e/lib/SettingRepository.ts index 3bdf6d2..87fb50b 100644 --- a/e2e/lib/SettingRepository.ts +++ b/e2e/lib/SettingRepository.ts @@ -1,18 +1,15 @@ -import { JSONTextSettings, SettingSource } from '../../src/shared/SettingData'; -import Settings from '../../src/shared/settings/Settings'; +import { JSONTextSettings, SettingSource } from "../../src/shared/SettingData"; +import Settings from "../../src/shared/settings/Settings";  export default class SettingRepository { -  constructor( -    private readonly browser: any, -  ) { -  } +  constructor(private readonly browser: any) {}    async saveJSON(settings: Settings): Promise<void> {      await this.browser.storage.sync.set({        settings: {          source: SettingSource.JSON, -        json:  JSONTextSettings.fromSettings(settings).toJSONText(), -      } +        json: JSONTextSettings.fromSettings(settings).toJSONText(), +      },      });    }  } diff --git a/e2e/lib/TestServer.ts b/e2e/lib/TestServer.ts index 5b9eee3..e0c711b 100644 --- a/e2e/lib/TestServer.ts +++ b/e2e/lib/TestServer.ts @@ -1,6 +1,6 @@ -import * as http from 'http'; -import * as net from 'net' -import express from 'express'; +import * as http from "http"; +import * as net from "net"; +import express from "express";  type HandlerFunc = (req: express.Request, res: express.Response) => void; @@ -9,10 +9,7 @@ export default class TestServer {    private app: express.Application; -  constructor( -    private port = 0, -    private address = '127.0.0.1', -  ){ +  constructor(private port = 0, private address = "127.0.0.1") {      this.app = express();    } @@ -23,30 +20,30 @@ export default class TestServer {    receiveContent(path: string, content: string): TestServer {      this.app.get(path, (_req: express.Request, res: express.Response) => { -      res.status(200).send(content) +      res.status(200).send(content);      });      return this;    } -   -  url(path = '/'): string { + +  url(path = "/"): string {      if (!this.http) { -      throw new Error('http server not started'); +      throw new Error("http server not started");      }      const addr = this.http.address() as net.AddressInfo; -    return `http://${addr.address}:${addr.port}${path}` +    return `http://${addr.address}:${addr.port}${path}`;    } -  start(): Promise<void>  { +  start(): Promise<void> {      if (this.http) { -      throw new Error('http server already started'); +      throw new Error("http server already started");      } -    this.http = http.createServer(this.app) +    this.http = http.createServer(this.app);      return new Promise((resolve) => {        this.http!!.listen(this.port, this.address, () => {          resolve(); -      }) +      });      });    } @@ -59,6 +56,6 @@ export default class TestServer {          this.http = undefined;          resolve();        }); -    }) +    });    }  } diff --git a/e2e/lib/clipboard.ts b/e2e/lib/clipboard.ts index 297b71a..6cc94cb 100644 --- a/e2e/lib/clipboard.ts +++ b/e2e/lib/clipboard.ts @@ -1,18 +1,19 @@ -import { spawn } from 'child_process'; +import { spawn } from "child_process";  const readLinux = (): Promise<string> => { -  let stdout = '', stderr = ''; +  let stdout = "", +    stderr = "";    return new Promise((resolve) => { -    const xsel = spawn('xsel', ['--clipboard', '--output']); -    xsel.stdout.on('data', (data) => { +    const xsel = spawn("xsel", ["--clipboard", "--output"]); +    xsel.stdout.on("data", (data) => {        stdout += data;      }); -    xsel.stderr.on('data', (data) => { +    xsel.stderr.on("data", (data) => {        stderr += data;      }); -    xsel.on('close', (code) => { +    xsel.on("close", (code) => {        if (code !== 0) { -        throw new Error(`xsel returns ${code}: ${stderr}`) +        throw new Error(`xsel returns ${code}: ${stderr}`);        }        resolve(stdout);      }); @@ -20,15 +21,15 @@ const readLinux = (): Promise<string> => {  };  const writeLinux = (data: string): Promise<string> => { -  let stderr = ''; +  let stderr = "";    return new Promise((resolve) => { -    const xsel = spawn('xsel', ['--clipboard', '--input']); -    xsel.stderr.on('data', (data) => { +    const xsel = spawn("xsel", ["--clipboard", "--input"]); +    xsel.stderr.on("data", (data) => {        stderr += data;      }); -    xsel.on('close', (code) => { +    xsel.on("close", (code) => {        if (code !== 0) { -        throw new Error(`xsel returns ${code}: ${stderr}`) +        throw new Error(`xsel returns ${code}: ${stderr}`);        }        resolve();      }); @@ -38,18 +39,19 @@ const writeLinux = (data: string): Promise<string> => {  };  const readDarwin = (): Promise<string> => { -  let stdout = '', stderr = ''; +  let stdout = "", +    stderr = "";    return new Promise((resolve) => { -    const pbpaste = spawn('pbpaste'); -    pbpaste.stdout.on('data', (data) => { +    const pbpaste = spawn("pbpaste"); +    pbpaste.stdout.on("data", (data) => {        stdout += data;      }); -    pbpaste.stderr.on('data', (data) => { +    pbpaste.stderr.on("data", (data) => {        stderr += data;      }); -    pbpaste.on('close', (code) => { +    pbpaste.on("close", (code) => {        if (code !== 0) { -        throw new Error(`pbpaste returns ${code}: ${stderr}`) +        throw new Error(`pbpaste returns ${code}: ${stderr}`);        }        resolve(stdout);      }); @@ -57,15 +59,15 @@ const readDarwin = (): Promise<string> => {  };  const writeDarwin = (data: string): Promise<string> => { -  let stderr = ''; +  let stderr = "";    return new Promise((resolve) => { -    const pbcopy = spawn('pbcopy'); -    pbcopy.stderr.on('data', (data) => { +    const pbcopy = spawn("pbcopy"); +    pbcopy.stderr.on("data", (data) => {        stderr += data;      }); -    pbcopy.on('close', (code) => { +    pbcopy.on("close", (code) => {        if (code !== 0) { -        throw new Error(`pbcopy returns ${code}: ${stderr}`) +        throw new Error(`pbcopy returns ${code}: ${stderr}`);        }        resolve();      }); @@ -83,25 +85,22 @@ class UnsupportedError extends Error {  const read = () => {    switch (process.platform) { -  case 'linux': -    return readLinux(); -  case 'darwin': -    return readDarwin(); +    case "linux": +      return readLinux(); +    case "darwin": +      return readDarwin();    }    throw new UnsupportedError(process.platform); -} +};  const write = (data: string) => {    switch (process.platform) { -  case 'linux': -    return writeLinux(data); -  case 'darwin': -    return writeDarwin(data); +    case "linux": +      return writeLinux(data); +    case "darwin": +      return writeDarwin(data);    }    throw new UnsupportedError(process.platform); -} - -export { -  read, -  write,  }; + +export { read, write }; | 
