Skip to content

Commit

Permalink
✨ Browserify @percy/sdk-utils (#265)
Browse files Browse the repository at this point in the history
* ✨ Browserify @percy/sdk-utils

* ♻ Split up and refactor @percy/sdk-utils

* 🔧 Allow registering scripts as karma hooks

* ✅ Update @percy/sdk-utils tests and bundle test helpers

* 📝 Update @percy/sdk-utils readme
  • Loading branch information
Wil Wilsman authored Mar 25, 2021
1 parent dc9cbe5 commit cd0b888
Show file tree
Hide file tree
Showing 14 changed files with 653 additions and 249 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ oclif.manifest.json
.DS_Store
.local-chromium
packages/logger/test/client.js
packages/sdk-utils/test/client.js
95 changes: 64 additions & 31 deletions packages/sdk-utils/README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,53 @@
# @percy/sdk-utils

Common Node SDK utils
Common JavaScript SDK utils

- [Usage](#usage)
- [`logger()`](#loggerdebug)
- [`getInfo()`](#getinfo)
- [`percy`](#percy)
- [`isPercyEnabled()`](#ispercyenabled)
- [`postSnapshot()`](#postsnapshot)
- [`request`](#requesturl-options)

## Usage

### `logger([debug])`

This function is a direct export of [`@percy/logger`](./packages/logger).

### `getInfo()`
### `percy`

Returns information about any running Percy CLI server. Some information is only available after
[`isPercyEnabled`](#ispercyenabled) has been called.
This object contains information about the local Percy environment and is updated when
[`isPercyEnabled`](#ispercyenabled) is called for the first time.

``` js
const { getInfo } = require('@percy/sdk-utils');
const { percy } = require('@percy/sdk-utils')

const { cliApi, loglevel, version, config } = getInfo();
```

#### Returned properties

- `cliApi` — CLI API address (`process.env.PERCY_SERVER_ADDRESS || 'http://localhost:5338'`)
- `loglevel` — CLI log level (`process.env.PERCY_LOGLEVEL || 'info'`)
// reflects/updates process.env.PERCY_SERVER_ADDRESS
percy.address === 'http://localhost:5338'

The following properties are only populated after [`isPercyEnabled`](#ispercyenabled) has been
called.
// updated after isPercyEnabled() is called
percy.enabled === true|false
percy.version.major === 1
percy.version.minor === 2
percy.version.patch === 3
percy.version.toString() === '1.2.3'
percy.config === {} // .percy.yml config

- `version` — CLI version parts (e.g. `['1', '0', '0']`)
- `config` — CLI config options
// updated after fetchPercyDOM() is called
percy.domScript === fs.readFile(require.resolve('@percy/dom'))
```

### `isPercyEnabled()`

Returns `true` or `false` if the Percy CLI API server is running. Calls the server's `/healthcheck`
endpoint and populates information for [`getInfo`](#getInfo). The result of this function is cached
and subsequent calls will return the first cached result. If the healthcheck fails, will log a
message unless the CLI loglevel is `quiet` or `silent`.
endpoint and populates information for the [`percy`](#percy) property. The result of this function
is cached and subsequent calls will return the first cached result. If the healthcheck fails, will
log a message unless the CLI loglevel is `quiet` or `silent`. Upon a successful health check, a
remote logging connection is also established.

``` js
const { isPercyEnabled } = require('@percy/sdk-utils');
const { isPercyEnabled } = require('@percy/sdk-utils')

// CLI API not running
await isPercyEnabled() === false
Expand All @@ -56,32 +59,32 @@ await isPercyEnabled() === true

### `fetchPercyDOM()`

Fetches and returns the `@percy/dom` serialization script hosted by the CLI API server. The
Fetches and returns the `@percy/dom` serialization script hosted by the local Percy API server. The
resulting string can be evaulated within a browser context to add the `PercyDOM.serialize` function
to the global scope. Subsequent calls return the first cached result.

``` js
const { fetchPercyDOM } = require('@percy/sdk-utils');
const { fetchPercyDOM } = require('@percy/sdk-utils')

let script = await fetchPercyDOM();
let script = await fetchPercyDOM()

// selenium-webdriver
driver.executeScript(script);
driver.executeScript(script)
// webdriverio
browser.execute(script);
browser.execute(script)
// puppeteer
page.evaluate(script);
page.evaluate(script)
// protractor
browser.executeScript(script);
browser.executeScript(script)
// etc...
```

### `postSnapshot(options)`

Posts snapshot options to the CLI API server.
Posts snapshot options to the local Percy API server.

``` js
const { postSnapshot } = require('@percy/sdk-utils');
const { postSnapshot } = require('@percy/sdk-utils')

await postSnapshot({
// required
Expand All @@ -95,5 +98,35 @@ await postSnapshot({
minHeight: 1024,
enableJavaScript: false,
requestHeaders: {}
});
})
```

### `request(url[, options])`

Sends a request to the local Percy API server. Used internally by the other SDK utils.

``` js
const { request } = require('@percy/sdk-utils')

await request('/percy/idle')
await request('/percy/stop')
```

#### `request.fetch(url, options)`

The underlying implementation of the `request()` util. For Node environments, `http.request` is
used; for browser environments, `window.fetch` is used. Can be overridden by the SDK's framework to
work around CORS/CSP issues.

The returned object must contain the following normalized properties from the request response:
`status`, `statusText`, `headers`, `body`

``` js
const { request } = require('@percy/sdk-utils')

// Cypress SDK example
request.fetch = async function fetch(url, options) {
options = { url, retryOnNetworkFailure: false, ...options }
return Cypress.backend('http:request', options)
}
```
112 changes: 0 additions & 112 deletions packages/sdk-utils/index.js

This file was deleted.

28 changes: 25 additions & 3 deletions packages/sdk-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,44 @@
"name": "@percy/sdk-utils",
"version": "1.0.0-beta.42",
"license": "MIT",
"main": "index.js",
"main": "dist/index.js",
"browser": "dist/bundle.js",
"files": [
"index.js",
"test/helpers.js"
"dist",
"test/helpers.js",
"test/server.js",
"test/client.js"
],
"engines": {
"node": ">=12"
},
"scripts": {
"build": "node ../../scripts/build",
"lint": "eslint --ignore-path ../../.gitignore .",
"test": "node ../../scripts/test",
"test:coverage": "yarn test --coverage"
},
"publishConfig": {
"access": "public"
},
"karma": {
"run_start": "node test/server start &",
"run_complete": "node test/server stop"
},
"rollup": {
"external": ["ws"],
"output": {
"name": "PercySDKUtils"
},
"test": {
"external": ["@percy/logger", "test/server"],
"output": {
"globals": {
"@percy/logger": "PercySDKUtils.logger"
}
}
}
},
"dependencies": {
"@percy/logger": "^1.0.0-beta.42"
}
Expand Down
24 changes: 24 additions & 0 deletions packages/sdk-utils/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import logger from '@percy/logger';
import percy from './percy-info';
import request from './request';
import isPercyEnabled from './percy-enabled';
import fetchPercyDOM from './percy-dom';
import postSnapshot from './post-snapshot';

export {
logger,
percy,
request,
isPercyEnabled,
fetchPercyDOM,
postSnapshot
};

export default {
logger,
percy,
request,
isPercyEnabled,
fetchPercyDOM,
postSnapshot
};
12 changes: 12 additions & 0 deletions packages/sdk-utils/src/percy-dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import percy from './percy-info';
import request from './request';

// Fetch and cache the @percy/dom script
export default async function fetchPercyDOM() {
if (percy.domScript == null) {
let response = await request('/percy/dom.js');
percy.domScript = response.body;
}

return percy.domScript;
}
Loading

0 comments on commit cd0b888

Please sign in to comment.