html-browser-tester 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/release-drafter.yml +22 -0
- package/.github/workflows/pr.yml +47 -0
- package/.github/workflows/publish.yml +53 -0
- package/.github/workflows/version-check.yml +26 -0
- package/README.md +63 -0
- package/index.html +13 -0
- package/package.json +16 -0
- package/src/browser-test.ts +112 -0
- package/src/expect/assert.ts +62 -0
- package/src/expect/index.ts +40 -0
- package/src/main.ts +49 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +22 -0
- package/utility/version-check.js +10 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
name-template: 'v$RESOLVED_VERSION 🌈'
|
2
|
+
tag-template: 'v$RESOLVED_VERSION'
|
3
|
+
exclude-labels:
|
4
|
+
- 'release'
|
5
|
+
- 'auto'
|
6
|
+
categories:
|
7
|
+
- title: '🚀 Features'
|
8
|
+
labels:
|
9
|
+
- 'feature'
|
10
|
+
- 'enhancement'
|
11
|
+
- title: '🐛 Bug Fixes'
|
12
|
+
labels:
|
13
|
+
- 'fix'
|
14
|
+
- 'bugfix'
|
15
|
+
- 'bug'
|
16
|
+
- title: '🧰 Maintenance'
|
17
|
+
label: 'chore'
|
18
|
+
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
19
|
+
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
|
20
|
+
template: |
|
21
|
+
## Changes
|
22
|
+
$CHANGES
|
@@ -0,0 +1,47 @@
|
|
1
|
+
name: PR
|
2
|
+
env:
|
3
|
+
CI: true
|
4
|
+
# preview環境更新および、stage環境やproduction環境の更新を行うworkflow
|
5
|
+
on:
|
6
|
+
push:
|
7
|
+
branches:
|
8
|
+
- master
|
9
|
+
- develop
|
10
|
+
pull_request:
|
11
|
+
branches:
|
12
|
+
- master
|
13
|
+
- develop
|
14
|
+
types:
|
15
|
+
- opened
|
16
|
+
- synchronize
|
17
|
+
- closed
|
18
|
+
- labeled
|
19
|
+
- unlabeled
|
20
|
+
tags:
|
21
|
+
- "!*"
|
22
|
+
jobs:
|
23
|
+
release:
|
24
|
+
name: Setup
|
25
|
+
runs-on: ubuntu-latest
|
26
|
+
steps:
|
27
|
+
- name: check label
|
28
|
+
if: |
|
29
|
+
github.event_name == 'pull_request' &&
|
30
|
+
!contains(github.event.pull_request.labels.*.name, 'fix') &&
|
31
|
+
!contains(github.event.pull_request.labels.*.name, 'bugfix') &&
|
32
|
+
!contains(github.event.pull_request.labels.*.name, 'enhancement') &&
|
33
|
+
!contains(github.event.pull_request.labels.*.name, 'chore') &&
|
34
|
+
!contains(github.event.pull_request.labels.*.name, 'feature') &&
|
35
|
+
!contains(github.event.pull_request.labels.*.name, 'release') &&
|
36
|
+
!contains(github.event.pull_request.labels.*.name, 'auto')
|
37
|
+
env:
|
38
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
39
|
+
URL: ${{ github.event.pull_request.comments_url }}
|
40
|
+
run: |
|
41
|
+
echo "Please add one of the following labels: fix, bugfix, enhancement, chore, feature, release" >> comments
|
42
|
+
sed -i -z 's/\n/\\n/g' comments
|
43
|
+
curl -X POST \
|
44
|
+
-H "Authorization: token ${GITHUB_TOKEN}" \
|
45
|
+
-d "{\"body\": \"$(cat comments)\"}" \
|
46
|
+
${URL}
|
47
|
+
exit 1
|
@@ -0,0 +1,53 @@
|
|
1
|
+
name: Publish
|
2
|
+
env:
|
3
|
+
CI: true
|
4
|
+
# masterブランチにpushした時のみ実行するワークフロー
|
5
|
+
on:
|
6
|
+
push:
|
7
|
+
branches:
|
8
|
+
- master
|
9
|
+
tags:
|
10
|
+
- "!*"
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
release:
|
14
|
+
name: Setup
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
steps:
|
17
|
+
- name: checkout
|
18
|
+
uses: actions/checkout@v1
|
19
|
+
- name: setup Node
|
20
|
+
uses: actions/setup-node@v1
|
21
|
+
with:
|
22
|
+
node-version: 16.x
|
23
|
+
registry-url: 'https://registry.npmjs.org'
|
24
|
+
- name: install
|
25
|
+
run: yarn --frozen-lockfile
|
26
|
+
# まだtagがないバージョンなら、Git Tagをpushする
|
27
|
+
- name: package-version
|
28
|
+
run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV
|
29
|
+
- name: package-version-to-git-tag
|
30
|
+
uses: pkgdeps/action-package-version-to-git-tag@v1
|
31
|
+
with:
|
32
|
+
github_token: ${{ secrets.GITHUB_TOKEN }}
|
33
|
+
github_repo: ${{ github.repository }}
|
34
|
+
git_commit_sha: ${{ github.sha }}
|
35
|
+
git_tag_prefix: ""
|
36
|
+
version: ${{ env.PACKAGE_VERSION }}
|
37
|
+
- name: get-npm-version
|
38
|
+
id: package-version
|
39
|
+
uses: martinbeentjes/npm-get-version-action@master
|
40
|
+
- name: create draft
|
41
|
+
uses: release-drafter/release-drafter@v5
|
42
|
+
with:
|
43
|
+
version: ${{ steps.package-version.outputs.current-version }}
|
44
|
+
name: ${{ steps.package-version.outputs.current-version }}
|
45
|
+
tag: ${{ steps.package-version.outputs.current-version }}
|
46
|
+
env:
|
47
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
48
|
+
- name: build lib
|
49
|
+
run: npm run build:lib
|
50
|
+
- name: publish to npm
|
51
|
+
run: npm publish
|
52
|
+
env:
|
53
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: Version Check
|
2
|
+
on:
|
3
|
+
pull_request:
|
4
|
+
branches:
|
5
|
+
- master
|
6
|
+
types:
|
7
|
+
- opened
|
8
|
+
- synchronize
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
auto-bumping:
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
steps:
|
14
|
+
- name: checkout
|
15
|
+
uses: actions/checkout@v1
|
16
|
+
- name: setup Node
|
17
|
+
uses: actions/setup-node@v1
|
18
|
+
with:
|
19
|
+
node-version: 16.x
|
20
|
+
registry-url: 'https://npm.pkg.github.com'
|
21
|
+
- name: install
|
22
|
+
run: yarn --frozen-lockfile
|
23
|
+
- name: version check
|
24
|
+
run: BRANCH_NAME=$HEAD_BRANCH node ./utility/version-check.js
|
25
|
+
env:
|
26
|
+
HEAD_BRANCH: ${{ github.head_ref }}
|
package/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# HTML Browser Tester
|
2
|
+
|
3
|
+
HTML Based browser tester without Node.js
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
```
|
8
|
+
npm install html-browser-tester
|
9
|
+
```
|
10
|
+
|
11
|
+
## Example
|
12
|
+
|
13
|
+
```js
|
14
|
+
import { BrowserTester } from 'html-browser-tester'
|
15
|
+
|
16
|
+
const html = `
|
17
|
+
<!DOCTYPE html>
|
18
|
+
<html lang="ja">
|
19
|
+
<head>
|
20
|
+
<meta charset="UTF-8">
|
21
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
23
|
+
<title>Hello</title>
|
24
|
+
<style>
|
25
|
+
h1 {
|
26
|
+
color: #000;
|
27
|
+
}
|
28
|
+
</style>
|
29
|
+
</head>
|
30
|
+
<body>
|
31
|
+
<h1>Title1</h1>
|
32
|
+
<h2>Title2</h2>
|
33
|
+
</body>
|
34
|
+
</html>
|
35
|
+
`
|
36
|
+
|
37
|
+
const main = async () => {
|
38
|
+
const browserTester = new BrowserTesterer({ html, width: 980, height: 980 })
|
39
|
+
|
40
|
+
browserTester.test('h1,h2 textContent should have right textContent', async (_, doc) => {
|
41
|
+
const h1 = doc.querySelector('h1')
|
42
|
+
const h2 = doc.querySelector('h2')
|
43
|
+
browserTester.expect(h1?.textContent).toBe('Title1')
|
44
|
+
browserTester.expect(h2?.textContent).toBe('Title2')
|
45
|
+
})
|
46
|
+
|
47
|
+
browserTester.test('title should have right textContent', async (_, doc) => {
|
48
|
+
const title = doc.querySelector('title')
|
49
|
+
browserTester.expect(title?.textContent).toBe('Hello')
|
50
|
+
})
|
51
|
+
|
52
|
+
browserTester.test('h2 should have red text', async (window, doc) => {
|
53
|
+
const h2 = doc.querySelector('h2')
|
54
|
+
browserTest.expect(window.getComputedStyle(h2).color).toBe('rgb(255, 0, 0)')
|
55
|
+
})
|
56
|
+
|
57
|
+
const results = await browserTester.run()
|
58
|
+
|
59
|
+
console.log(results)
|
60
|
+
}
|
61
|
+
|
62
|
+
main()
|
63
|
+
```
|
package/index.html
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8" />
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
7
|
+
<title>Vite + TS</title>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<div id="app"></div>
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
12
|
+
</body>
|
13
|
+
</html>
|
package/package.json
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"name": "html-browser-tester",
|
3
|
+
"main": "./lib/browser-test.js",
|
4
|
+
"types": "./lib/browser-test.d.ts",
|
5
|
+
"version": "0.0.1",
|
6
|
+
"scripts": {
|
7
|
+
"dev": "vite",
|
8
|
+
"preview": "vite preview",
|
9
|
+
"build:lib": "tsc"
|
10
|
+
},
|
11
|
+
"devDependencies": {
|
12
|
+
"typescript": "^4.6.4",
|
13
|
+
"vite": "^3.2.3"
|
14
|
+
},
|
15
|
+
"dependencies": {}
|
16
|
+
}
|
@@ -0,0 +1,112 @@
|
|
1
|
+
import { Expect } from "./expect";
|
2
|
+
|
3
|
+
type Option = {
|
4
|
+
html: string;
|
5
|
+
width?: number;
|
6
|
+
height?: number;
|
7
|
+
}
|
8
|
+
|
9
|
+
type Result = {
|
10
|
+
description: string;
|
11
|
+
result: boolean;
|
12
|
+
}
|
13
|
+
|
14
|
+
type Test = {
|
15
|
+
description: string;
|
16
|
+
callback: (window: Window, doc: Document) => Promise<void>
|
17
|
+
}
|
18
|
+
|
19
|
+
export class BrowserTester {
|
20
|
+
private html = '';
|
21
|
+
private width?: number;
|
22
|
+
private height?: number;
|
23
|
+
private iframe!: HTMLIFrameElement;
|
24
|
+
private tests: Test[] = []
|
25
|
+
private expects = new Expect()
|
26
|
+
private beforeEachCallbacks: ((window: Window, doc: Document) => Promise<void>)[] = []
|
27
|
+
private afterEachCallbacks: ((window: Window, doc: Document) => Promise<void>)[] = []
|
28
|
+
|
29
|
+
constructor({
|
30
|
+
html = '',
|
31
|
+
width,
|
32
|
+
height,
|
33
|
+
}: Option) {
|
34
|
+
this.html = html
|
35
|
+
if (width) {
|
36
|
+
this.width = width
|
37
|
+
}
|
38
|
+
if (height) {
|
39
|
+
this.height = height
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
setBrowserSize(width: number, height: number) {
|
44
|
+
if (width) {
|
45
|
+
this.iframe.width = `${width}px`
|
46
|
+
}
|
47
|
+
if (height) {
|
48
|
+
this.iframe.height = `${height}px`
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
beforeEach(callback: (window: Window, doc: Document) => Promise<void>) {
|
53
|
+
this.beforeEachCallbacks.push(callback)
|
54
|
+
}
|
55
|
+
|
56
|
+
afterEach(callback: (window: Window, doc: Document) => Promise<void>) {
|
57
|
+
this.afterEachCallbacks.push(callback)
|
58
|
+
}
|
59
|
+
|
60
|
+
test(description: string, callback: (window: Window, doc: Document) => Promise<void>) {
|
61
|
+
this.tests.push({
|
62
|
+
description,
|
63
|
+
callback,
|
64
|
+
})
|
65
|
+
}
|
66
|
+
|
67
|
+
expect(value: unknown) {
|
68
|
+
return this.expects.expect(value)
|
69
|
+
}
|
70
|
+
|
71
|
+
run() {
|
72
|
+
return new Promise<Result[]>((resolve) => {
|
73
|
+
const blob = new Blob(
|
74
|
+
[this.html],
|
75
|
+
{ type: "text/html" }
|
76
|
+
);
|
77
|
+
const url = URL.createObjectURL(blob);
|
78
|
+
const iframe = document.createElement('iframe')
|
79
|
+
const body = document.querySelector('body') as HTMLBodyElement
|
80
|
+
this.iframe = iframe
|
81
|
+
iframe.src = url
|
82
|
+
if (this.width && this.height) {
|
83
|
+
iframe.width = `${this.width}px`
|
84
|
+
iframe.height = `${this.height}px`
|
85
|
+
}
|
86
|
+
const iframeCallback = async () => {
|
87
|
+
const results: Result[] = []
|
88
|
+
for (const t of this.tests) {
|
89
|
+
for (const b of this.beforeEachCallbacks) {
|
90
|
+
await b(iframe.contentWindow as Window, iframe.contentDocument as Document)
|
91
|
+
}
|
92
|
+
await t.callback(iframe.contentWindow as Window, iframe.contentDocument as Document)
|
93
|
+
const { description } = t
|
94
|
+
results.push({
|
95
|
+
description,
|
96
|
+
result: this.expects.isAllPassed()
|
97
|
+
})
|
98
|
+
this.expects.clean()
|
99
|
+
for (const a of this.afterEachCallbacks) {
|
100
|
+
await a(iframe.contentWindow as Window, iframe.contentDocument as Document)
|
101
|
+
}
|
102
|
+
}
|
103
|
+
iframe.removeEventListener('load', iframeCallback)
|
104
|
+
URL.revokeObjectURL(url)
|
105
|
+
iframe.remove()
|
106
|
+
resolve(results)
|
107
|
+
}
|
108
|
+
iframe.addEventListener('load', iframeCallback)
|
109
|
+
body.appendChild(iframe)
|
110
|
+
})
|
111
|
+
}
|
112
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
export const assert = (expected: unknown) => ({
|
2
|
+
toBe: (resut: unknown) => {
|
3
|
+
return expected === resut
|
4
|
+
},
|
5
|
+
toBeTruthy: (result: unknown) => {
|
6
|
+
return result === true
|
7
|
+
},
|
8
|
+
toBeFalsy: (result: unknown) => {
|
9
|
+
return result === false
|
10
|
+
},
|
11
|
+
toBeNull: (result: unknown) => {
|
12
|
+
return result === null
|
13
|
+
},
|
14
|
+
toBeUndefined: (result: unknown) => {
|
15
|
+
return result === undefined
|
16
|
+
},
|
17
|
+
toBeDefined: (result: unknown) => {
|
18
|
+
return result !== undefined
|
19
|
+
},
|
20
|
+
toBeNaN: (result: unknown) => {
|
21
|
+
return result === NaN
|
22
|
+
},
|
23
|
+
toContain: (result: unknown) => {
|
24
|
+
if (Array.isArray(expected)) {
|
25
|
+
expected.some(item => item === result)
|
26
|
+
}
|
27
|
+
return false
|
28
|
+
},
|
29
|
+
toBeLessThan: (result: unknown) => {
|
30
|
+
if (typeof expected === 'number' && typeof result === 'number') {
|
31
|
+
return expected < result
|
32
|
+
}
|
33
|
+
return false
|
34
|
+
},
|
35
|
+
toBeGreaterThan: (result: unknown) => {
|
36
|
+
if (typeof expected === 'number' && typeof result === 'number') {
|
37
|
+
return expected > result
|
38
|
+
}
|
39
|
+
return false
|
40
|
+
},
|
41
|
+
toBeLessThanOrEqual: (result: unknown) => {
|
42
|
+
if (typeof expected === 'number' && typeof result === 'number') {
|
43
|
+
return expected <= result
|
44
|
+
}
|
45
|
+
return false
|
46
|
+
},
|
47
|
+
toBeGreaterThanOrEqual: (result: unknown) => {
|
48
|
+
if (typeof expected === 'number' && typeof result === 'number') {
|
49
|
+
return expected >= result
|
50
|
+
}
|
51
|
+
return false
|
52
|
+
},
|
53
|
+
toBeInstanceOf: (result: unknown) => {
|
54
|
+
if (typeof result !== 'function') {
|
55
|
+
return false
|
56
|
+
}
|
57
|
+
if (expected instanceof result) {
|
58
|
+
return true
|
59
|
+
}
|
60
|
+
return false
|
61
|
+
},
|
62
|
+
})
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { assert } from './assert';
|
2
|
+
|
3
|
+
type AssertKey = keyof ReturnType<typeof assert>
|
4
|
+
type TruthyAssertObject = { [T in AssertKey]: (value: unknown) => void }
|
5
|
+
|
6
|
+
type ReturnObject =
|
7
|
+
TruthyAssertObject
|
8
|
+
& {
|
9
|
+
not: TruthyAssertObject
|
10
|
+
}
|
11
|
+
|
12
|
+
export class Expect {
|
13
|
+
private expects: boolean[] = []
|
14
|
+
|
15
|
+
expect(expected: unknown) {
|
16
|
+
const assertedObject = assert(expected)
|
17
|
+
const returnObject = {
|
18
|
+
not: {},
|
19
|
+
} as ReturnObject;
|
20
|
+
(Object.keys(assertedObject) as AssertKey[]).forEach((key) => {
|
21
|
+
returnObject[key] = (result: unknown) => {
|
22
|
+
this.expects.push(assertedObject[key](result))
|
23
|
+
}
|
24
|
+
})
|
25
|
+
;(Object.keys(assertedObject) as AssertKey[]).forEach((key) => {
|
26
|
+
returnObject.not[key] = (result: unknown) => {
|
27
|
+
this.expects.push(!assertedObject[key](result))
|
28
|
+
}
|
29
|
+
})
|
30
|
+
return returnObject;
|
31
|
+
}
|
32
|
+
|
33
|
+
clean() {
|
34
|
+
this.expects = []
|
35
|
+
}
|
36
|
+
|
37
|
+
isAllPassed() {
|
38
|
+
return this.expects.every(e => e)
|
39
|
+
}
|
40
|
+
}
|
package/src/main.ts
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
import { BrowserTester } from "./browser-test";
|
2
|
+
|
3
|
+
const html = `
|
4
|
+
<!DOCTYPE html>
|
5
|
+
<html lang="ja">
|
6
|
+
<head>
|
7
|
+
<meta charset="UTF-8">
|
8
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
10
|
+
<title>Hello</title>
|
11
|
+
<style>
|
12
|
+
h2 {
|
13
|
+
color: red;
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
</head>
|
17
|
+
<body>
|
18
|
+
<h1>Title1</h1>
|
19
|
+
<h2>Title2</h2>
|
20
|
+
</body>
|
21
|
+
</html>
|
22
|
+
`
|
23
|
+
|
24
|
+
const main = async () => {
|
25
|
+
const browserTest = new BrowserTester({ html, width: 980, height: 980 })
|
26
|
+
|
27
|
+
browserTest.test('h1,h2 textContent should have right textContent', async (_, doc) => {
|
28
|
+
const h1 = doc.querySelector('h1')
|
29
|
+
const h2 = doc.querySelector('h2')
|
30
|
+
browserTest.expect(h1?.textContent).toBe('Title1')
|
31
|
+
browserTest.expect(h2?.textContent).toBe('Title2')
|
32
|
+
})
|
33
|
+
|
34
|
+
browserTest.test('title should have right textContent', async (_, doc) => {
|
35
|
+
const title = doc.querySelector('title')
|
36
|
+
browserTest.expect(title?.textContent).toBe('Hello')
|
37
|
+
})
|
38
|
+
|
39
|
+
browserTest.test('h2 should have red text', async (window, doc) => {
|
40
|
+
const h2 = doc.querySelector('h2') as HTMLHeadingElement
|
41
|
+
browserTest.expect(window.getComputedStyle(h2).color).toBe('rgb(255, 0, 0)')
|
42
|
+
})
|
43
|
+
|
44
|
+
const results = await browserTest.run()
|
45
|
+
|
46
|
+
console.log(results)
|
47
|
+
}
|
48
|
+
|
49
|
+
main()
|
@@ -0,0 +1 @@
|
|
1
|
+
/// <reference types="vite/client" />
|
package/tsconfig.json
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"compilerOptions": {
|
3
|
+
"target": "ES2022",
|
4
|
+
"useDefineForClassFields": true,
|
5
|
+
"module": "ES2022",
|
6
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
7
|
+
"declaration": true,
|
8
|
+
"declarationDir": "./lib",
|
9
|
+
"moduleResolution": "Node",
|
10
|
+
"strict": true,
|
11
|
+
"outDir": "./lib",
|
12
|
+
"resolveJsonModule": true,
|
13
|
+
"isolatedModules": true,
|
14
|
+
"esModuleInterop": true,
|
15
|
+
"noEmit": false,
|
16
|
+
"noUnusedLocals": true,
|
17
|
+
"noUnusedParameters": true,
|
18
|
+
"noImplicitReturns": true,
|
19
|
+
"skipLibCheck": true
|
20
|
+
},
|
21
|
+
"include": ["src"]
|
22
|
+
}
|