mirror of
https://github.com/tlsnotary/tlsn-js.git
synced 2026-01-08 04:03:53 -05:00
Use Playwright to test demos (#106)
* Run tests and demos with playwright * ci: renamed workflow * Improved demo readmes * Use a separate page for each test
This commit is contained in:
31
.github/workflows/ci.yaml
vendored
31
.github/workflows/ci.yaml
vendored
@@ -5,12 +5,6 @@ on:
|
|||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
env:
|
|
||||||
LOCAL-NOTARY: true
|
|
||||||
LOCAL-WS: false
|
|
||||||
HEADLESS: true
|
|
||||||
PUPPETEER_SKIP_DOWNLOAD: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-test:
|
build-and-test:
|
||||||
name: Build and test
|
name: Build and test
|
||||||
@@ -37,7 +31,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Install stable nightly toolchain
|
- name: Install stable nightly toolchain
|
||||||
@@ -61,27 +55,18 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: npm run lint
|
run: npm run lint
|
||||||
|
|
||||||
- name: Install Chrome
|
|
||||||
uses: browser-actions/setup-chrome@v1
|
|
||||||
id: setup-chrome
|
|
||||||
with:
|
|
||||||
chrome-version: 121.0.6167.85
|
|
||||||
|
|
||||||
- name: Set CHROME_PATH environment variable
|
- name: install wstcp
|
||||||
run: echo "CHROME_PATH=${{ steps.setup-chrome.outputs['chrome-path'] }}" >> $GITHUB_ENV
|
run: cargo install wstcp
|
||||||
|
|
||||||
|
- name: Install Chromium (Playwright)
|
||||||
|
run: npx playwright install --with-deps chromium
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
run: |
|
run: npm run test
|
||||||
# Install wstcp and use it in the background
|
|
||||||
cargo install wstcp
|
|
||||||
wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443 &
|
|
||||||
WSTCP_PID=$!
|
|
||||||
trap "kill $WSTCP_PID" EXIT
|
|
||||||
npm run test
|
|
||||||
|
|
||||||
- name: Determine release type (dry-run or publish)
|
- name: Determine release type (dry-run or publish)
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
54
.github/workflows/playwright.yml
vendored
Normal file
54
.github/workflows/playwright.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
name: Tests demos
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
timeout-minutes: 60
|
||||||
|
name: Tests demos
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
notary-server:
|
||||||
|
image: ghcr.io/tlsnotary/tlsn/notary-server:v0.1.0-alpha.10
|
||||||
|
env:
|
||||||
|
NOTARY_SERVER__TLS__ENABLED: false
|
||||||
|
ports:
|
||||||
|
- 7047:7047
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: lts/*
|
||||||
|
- name: build tlsn-js
|
||||||
|
run: npm ci; npm run build
|
||||||
|
- name: install wstcp
|
||||||
|
run: cargo install wstcp
|
||||||
|
- name: Install Chromium (Playwright)
|
||||||
|
run: npx playwright install --with-deps chromium
|
||||||
|
- name: Test react demo
|
||||||
|
working-directory: demo/react-ts-webpack
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
npm i
|
||||||
|
npm run test
|
||||||
|
- name: Test interactive verifier demo
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
cd demo/interactive-demo/verifier-rs
|
||||||
|
cargo build --release
|
||||||
|
cd ../prover-ts
|
||||||
|
npm i
|
||||||
|
npm run test
|
||||||
|
- name: Test web-to-web p2p demo
|
||||||
|
working-directory: demo/react-ts-webpack
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
npm run test
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
with:
|
||||||
|
name: playwright-report
|
||||||
|
path: '**/playwright-report/'
|
||||||
|
retention-days: 30
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -6,4 +6,10 @@ dev-build/
|
|||||||
test-build/
|
test-build/
|
||||||
./demo/node_modules
|
./demo/node_modules
|
||||||
utils/tlsn
|
utils/tlsn
|
||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|||||||
@@ -1,38 +1,59 @@
|
|||||||
# Test Rust Prover
|
# Interactive Verifier Demo
|
||||||
|
|
||||||
1. Start the verifier:
|
This demo shows how to use TLSNotary **without a notary**: a direct proof between a prover and a verifier, where the verifier checks both the TLS session and the revealed data.
|
||||||
```bash
|
|
||||||
cd verifier-rs; cargo run --release
|
|
||||||
```
|
|
||||||
2. Run the prover:
|
|
||||||
```bash
|
|
||||||
cd prover-rs; cargo run --release
|
|
||||||
```
|
|
||||||
|
|
||||||
# Test Browser Prover
|
There are two prover implementations:
|
||||||
1. Start the verifier:
|
- **Rust**
|
||||||
```bash
|
- **TypeScript** (browser)
|
||||||
cd verifier-rs; cargo run --release
|
The verifier is implemented in Rust.
|
||||||
```
|
|
||||||
2. Since a web browser doesn't have the ability to make TCP connection, we need to use a websocket proxy server to access <raw.githubusercontent.com>.
|
|
||||||
```bash
|
|
||||||
cargo install wstcp
|
|
||||||
|
|
||||||
wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443
|
---
|
||||||
```
|
|
||||||
3. Run the prover
|
## Interactive Verifier Demo with Rust Prover
|
||||||
1. Build tlsn-js
|
|
||||||
|
1. **Start the verifier:**
|
||||||
|
```bash
|
||||||
|
cd verifier-rs
|
||||||
|
cargo run --release
|
||||||
|
```
|
||||||
|
2. **Run the prover:**
|
||||||
|
```bash
|
||||||
|
cd prover-rs
|
||||||
|
cargo run --release
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Interactive Verifier Demo with TypeScript Prover (Browser)
|
||||||
|
|
||||||
|
1. **Start the verifier:**
|
||||||
|
```bash
|
||||||
|
cd verifier-rs
|
||||||
|
cargo run --release
|
||||||
|
```
|
||||||
|
2. **Set up a websocket proxy for raw.githubusercontent.com**
|
||||||
|
Browsers cannot make raw TCP connections, so a websocket proxy is required:
|
||||||
|
```bash
|
||||||
|
cargo install wstcp
|
||||||
|
wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443
|
||||||
|
```
|
||||||
|
3. **Run the prover in the browser:**
|
||||||
|
1. **Build tlsn-js**
|
||||||
```bash
|
```bash
|
||||||
cd ..
|
cd ..
|
||||||
npm i
|
npm install
|
||||||
npm run build
|
npm run build
|
||||||
npm link
|
|
||||||
```
|
```
|
||||||
2. Build demo prover-ts
|
2. **Build and start the TypeScript prover demo**
|
||||||
```bash
|
```bash
|
||||||
cd prover-ts
|
cd prover-ts
|
||||||
npm i
|
npm install
|
||||||
npm link
|
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
3. Open <http://localhost:3456/> and click **Start Prover**
|
3. **Open the demo in your browser:**
|
||||||
|
Go to [http://localhost:8080/](http://localhost:8080/) and click **Start Prover**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Tip:**
|
||||||
|
If you encounter issues, make sure all dependencies are installed and the websocket proxy is running before starting the browser demo.
|
||||||
|
|||||||
7
demo/interactive-demo/prover-ts/.gitignore
vendored
7
demo/interactive-demo/prover-ts/.gitignore
vendored
@@ -1 +1,8 @@
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
node_modules/
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>React/Typescript Example</title>
|
<title>TLSNotary React TypeScript Demo</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "webpack.js",
|
"main": "webpack.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack-dev-server --config webpack.js"
|
"dev": "webpack-dev-server --config webpack.js",
|
||||||
|
"start": "webpack serve --config webpack.js",
|
||||||
|
"test": "npx playwright test"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|||||||
90
demo/interactive-demo/prover-ts/playwright.config.ts
Normal file
90
demo/interactive-demo/prover-ts/playwright.config.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// import dotenv from 'dotenv';
|
||||||
|
// import path from 'path';
|
||||||
|
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
baseURL: 'http://localhost:8080',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'firefox',
|
||||||
|
// use: { ...devices['Desktop Firefox'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'webkit',
|
||||||
|
// use: { ...devices['Desktop Safari'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against mobile viewports. */
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: { ...devices['Pixel 5'] },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: { ...devices['iPhone 12'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: [
|
||||||
|
{
|
||||||
|
command: 'npm run start',
|
||||||
|
url: 'http://localhost:8080',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443',
|
||||||
|
reuseExistingServer: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'cargo run --release',
|
||||||
|
cwd: '../verifier-rs',
|
||||||
|
reuseExistingServer: true,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
@@ -224,7 +224,7 @@ function App(): ReactElement {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="bg-gray-100 border border-gray-300 p-4 rounded-lg mt-4">
|
<div className="bg-gray-100 border border-gray-300 p-4 rounded-lg mt-4">
|
||||||
<pre className="text-left text-sm text-gray-800 whitespace-pre-wrap overflow-auto">
|
<pre data-testid="proof-data" className="text-left text-sm text-gray-800 whitespace-pre-wrap overflow-auto">
|
||||||
{JSON.stringify(result, null, 2)}
|
{JSON.stringify(result, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
16
demo/interactive-demo/prover-ts/tests/demo-flow.spec.ts
Normal file
16
demo/interactive-demo/prover-ts/tests/demo-flow.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('has title', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page).toHaveTitle(/TLSNotary/)
|
||||||
|
});
|
||||||
|
|
||||||
|
test('run demo', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
// Click the get started link.
|
||||||
|
await page.getByRole('button', { name: 'Start Prover' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByTestId('proof-data')).toContainText('Unredacted data successfully revealed to Verifier', { timeout: 60000 });
|
||||||
|
|
||||||
|
});
|
||||||
7
demo/react-ts-webpack/.gitignore
vendored
7
demo/react-ts-webpack/.gitignore
vendored
@@ -1 +1,8 @@
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
node_modules/
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|||||||
79
demo/react-ts-webpack/README.md
Normal file
79
demo/react-ts-webpack/README.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# TLSNotary in React/TypeScript with `tlsn-js`
|
||||||
|
|
||||||
|
This demo shows how to use TLSNotary with a delegated verifier, also known as a **notary**.
|
||||||
|
In this demo, we request JSON data from a GitHub page, use `tlsn-js` to notarize the TLS request with TLSNotary, and display the attestation and revealed data.
|
||||||
|
|
||||||
|
> **Note:**
|
||||||
|
> This demo uses TLSNotary to notarize **public** data for simplicity. In real-world applications, TLSNotary is especially valuable for notarizing private and sensitive data.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Before running the demo, you need to start a local notary server and a websocket proxy. If you prefer to use the hosted test servers from PSE, see the section below.
|
||||||
|
|
||||||
|
### Websocket Proxy
|
||||||
|
|
||||||
|
Browsers cannot make raw TCP connections, so a websocket proxy server is required.
|
||||||
|
|
||||||
|
1. **Install [wstcp](https://github.com/sile/wstcp):**
|
||||||
|
```sh
|
||||||
|
cargo install wstcp
|
||||||
|
```
|
||||||
|
2. **Run a websocket proxy for `https://raw.githubusercontent.com`:**
|
||||||
|
```sh
|
||||||
|
wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443
|
||||||
|
```
|
||||||
|
> Note: The `raw.githubusercontent.com:443` argument specifies the server used in this quick start.
|
||||||
|
|
||||||
|
### Run a Local Notary Server
|
||||||
|
|
||||||
|
You also need to run a local notary server for this demo.
|
||||||
|
|
||||||
|
- **Using Git and Rust Cargo:**
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/tlsnotary/tlsn.git
|
||||||
|
cargo run --release --bin notary-server
|
||||||
|
```
|
||||||
|
- **Using Docker (from the root of the tlsn-js repo):**
|
||||||
|
```sh
|
||||||
|
npm run notary
|
||||||
|
```
|
||||||
|
|
||||||
|
The notary server will now be running in the background, waiting for connections.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use the PSE Web Proxy and Notary
|
||||||
|
|
||||||
|
If you want to use the hosted PSE notary and proxy:
|
||||||
|
|
||||||
|
1. Open `app.tsx` in your editor.
|
||||||
|
2. Replace the notary URL:
|
||||||
|
```ts
|
||||||
|
notaryUrl: 'https://notary.pse.dev/v0.1.0-alpha.10',
|
||||||
|
```
|
||||||
|
This uses the [PSE](https://pse.dev) notary server to notarize the API request. You can use a different or [local notary](#run-a-local-notary-server); a local server will be faster due to the high bandwidth and low network latency.
|
||||||
|
3. Replace the websocket proxy URL:
|
||||||
|
```ts
|
||||||
|
websocketProxyUrl: 'wss://notary.pse.dev/proxy?token=raw.githubusercontent.com',
|
||||||
|
```
|
||||||
|
This uses a proxy hosted by [PSE](https://pse.dev). You can use a different or local proxy if you prefer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Run the Demo
|
||||||
|
|
||||||
|
1. **Install dependencies:**
|
||||||
|
```sh
|
||||||
|
npm i
|
||||||
|
```
|
||||||
|
2. **Start the Webpack Dev Server:**
|
||||||
|
```sh
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
3. **Open the demo in your browser:**
|
||||||
|
Go to [http://localhost:8080](http://localhost:8080)
|
||||||
|
4. **Click the "Start demo" button**
|
||||||
|
5. **Open Developer Tools** and monitor the console logs
|
||||||
|
œœ
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>React/Typescrip Example</title>
|
<title>TLSNotary React TypeScript Demo</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
</script>
|
</script>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -5,16 +5,18 @@
|
|||||||
"main": "webpack.js",
|
"main": "webpack.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "webpack-dev-server --config webpack.js",
|
"dev": "webpack-dev-server --config webpack.js",
|
||||||
"build": "webpack --config webpack.js"
|
"build": "webpack --config webpack.js",
|
||||||
|
"start": "webpack serve --config webpack.js",
|
||||||
|
"test": "npx playwright test"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"comlink": "^4.4.1",
|
"comlink": "^4.4.1",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
|
"http-parser-js": "^0.5.9",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"postcss-loader": "^8.1.1",
|
"postcss-loader": "^8.1.1",
|
||||||
"http-parser-js": "^0.5.9",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-loader-spinner": "^6.1.6",
|
"react-loader-spinner": "^6.1.6",
|
||||||
@@ -25,6 +27,8 @@
|
|||||||
"tlsn-js": "../../"
|
"tlsn-js": "../../"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@playwright/test": "^1.52.0",
|
||||||
|
"@types/node": "^22.15.18",
|
||||||
"@types/react": "^18.0.26",
|
"@types/react": "^18.0.26",
|
||||||
"@types/react-dom": "^18.0.10",
|
"@types/react-dom": "^18.0.10",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
@@ -41,4 +45,4 @@
|
|||||||
"webpack-cli": "^4.10.0",
|
"webpack-cli": "^4.10.0",
|
||||||
"webpack-dev-server": "^4.11.1"
|
"webpack-dev-server": "^4.11.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
85
demo/react-ts-webpack/playwright.config.ts
Normal file
85
demo/react-ts-webpack/playwright.config.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// import dotenv from 'dotenv';
|
||||||
|
// import path from 'path';
|
||||||
|
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
baseURL: 'http://localhost:8080',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'firefox',
|
||||||
|
// use: { ...devices['Desktop Firefox'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'webkit',
|
||||||
|
// use: { ...devices['Desktop Safari'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against mobile viewports. */
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: { ...devices['Pixel 5'] },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: { ...devices['iPhone 12'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: [
|
||||||
|
{
|
||||||
|
command: 'npm run start',
|
||||||
|
url: 'http://localhost:8080',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443',
|
||||||
|
reuseExistingServer: true,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
@@ -140,6 +140,7 @@ function App(): ReactElement {
|
|||||||
const proof = await (Prover.notarize as typeof TProver.notarize)({
|
const proof = await (Prover.notarize as typeof TProver.notarize)({
|
||||||
notaryUrl: notaryUrl,
|
notaryUrl: notaryUrl,
|
||||||
websocketProxyUrl: websocketProxyUrl,
|
websocketProxyUrl: websocketProxyUrl,
|
||||||
|
maxRecvData: 2048,
|
||||||
url: serverUrl,
|
url: serverUrl,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -285,7 +286,7 @@ function App(): ReactElement {
|
|||||||
<summary className="cursor-pointer text-slate-600">
|
<summary className="cursor-pointer text-slate-600">
|
||||||
View Proof
|
View Proof
|
||||||
</summary>
|
</summary>
|
||||||
<pre
|
<pre data-testid="proof-data"
|
||||||
className="mt-2 p-2 bg-slate-100 rounded text-sm text-slate-800 overflow-auto"
|
className="mt-2 p-2 bg-slate-100 rounded text-sm text-slate-800 overflow-auto"
|
||||||
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
||||||
>
|
>
|
||||||
@@ -301,7 +302,7 @@ function App(): ReactElement {
|
|||||||
) : !result ? (
|
) : !result ? (
|
||||||
<i className="text-slate-500">verifying</i>
|
<i className="text-slate-500">verifying</i>
|
||||||
) : (
|
) : (
|
||||||
<pre
|
<pre data-testid="verify-data"
|
||||||
className="mt-2 p-2 bg-slate-100 rounded text-sm text-slate-800 overflow-auto"
|
className="mt-2 p-2 bg-slate-100 rounded text-sm text-slate-800 overflow-auto"
|
||||||
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}
|
||||||
>
|
>
|
||||||
|
|||||||
36
demo/react-ts-webpack/tests/demo-flow.spec.ts
Normal file
36
demo/react-ts-webpack/tests/demo-flow.spec.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('has title', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page).toHaveTitle(/TLSNotary React TypeScript Demo/)
|
||||||
|
});
|
||||||
|
|
||||||
|
test('run demo (normal)', async ({ page }) => {
|
||||||
|
test.setTimeout(60000);
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
// Click the get started link.
|
||||||
|
await page.getByRole('button', { name: 'Start Demo (Normal config)' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByTestId('proof-data')).toContainText('"data":', { timeout: 60000 });
|
||||||
|
|
||||||
|
let verify_data = await page.getByTestId('verify-data').innerText();
|
||||||
|
expect(verify_data).toContain('"serverName": "raw.githubusercontent.com"');
|
||||||
|
expect(verify_data).toContain('John Doe');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('run demo (helper)', async ({ page }) => {
|
||||||
|
test.setTimeout(60000);
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
// Click the get started link.
|
||||||
|
await page.getByRole('button', { name: 'Start Demo 2 (With helper method)' }).click();
|
||||||
|
|
||||||
|
await expect(page.getByTestId('proof-data')).toContainText('"data":', { timeout: 60000 });
|
||||||
|
|
||||||
|
// await page.screenshot({ path: 'screenshot.png', fullPage: true });
|
||||||
|
|
||||||
|
let verify_data = await page.getByTestId('verify-data').innerText();
|
||||||
|
expect(verify_data).toContain('"serverName": "raw.githubusercontent.com"');
|
||||||
|
expect(verify_data).toContain('"recv"');
|
||||||
|
});
|
||||||
7
demo/web-to-web-p2p/.gitignore
vendored
7
demo/web-to-web-p2p/.gitignore
vendored
@@ -1 +1,8 @@
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
|
# Playwright
|
||||||
|
node_modules/
|
||||||
|
/test-results/
|
||||||
|
/playwright-report/
|
||||||
|
/blob-report/
|
||||||
|
/playwright/.cache/
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ In this demo, the two web clients run in the same browser page (`./src/app.tsx`)
|
|||||||
npm i
|
npm i
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
2. Open <http://localhost:3456/>
|
2. Open <http://localhost:8080/>
|
||||||
3. Click the **Start Demo** button
|
3. Click the **Start Demo** button
|
||||||
|
|
||||||
The Prover window logs the Prover's output, the Verifier logs the Verifier's output. In the console view you can see the websocket log.
|
The Prover window logs the Prover's output, the Verifier logs the Verifier's output. In the console view you can see the websocket log.
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>React/Typescrip Example</title>
|
<title>Web-to-Web P2P Demo</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
</script>
|
</script>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
"dev:server": "node ./server/index.js",
|
"dev:server": "node ./server/index.js",
|
||||||
"dev:ui": "webpack-dev-server --config webpack.js",
|
"dev:ui": "webpack-dev-server --config webpack.js",
|
||||||
"dev": "concurrently npm:dev:ui npm:dev:server",
|
"dev": "concurrently npm:dev:ui npm:dev:server",
|
||||||
"build": "webpack --config webpack.js"
|
"build": "webpack --config webpack.js",
|
||||||
|
"start:ui": "webpack serve --config webpack.js",
|
||||||
|
"test": "npm run build && npx playwright test"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -45,4 +47,4 @@
|
|||||||
"webpack-cli": "^4.10.0",
|
"webpack-cli": "^4.10.0",
|
||||||
"webpack-dev-server": "^4.11.1"
|
"webpack-dev-server": "^4.11.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
90
demo/web-to-web-p2p/playwright.config.ts
Normal file
90
demo/web-to-web-p2p/playwright.config.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// import dotenv from 'dotenv';
|
||||||
|
// import path from 'path';
|
||||||
|
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
baseURL: 'http://localhost:8080',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'firefox',
|
||||||
|
// use: { ...devices['Desktop Firefox'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'webkit',
|
||||||
|
// use: { ...devices['Desktop Safari'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against mobile viewports. */
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: { ...devices['Pixel 5'] },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: { ...devices['iPhone 12'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: [
|
||||||
|
{
|
||||||
|
command: 'npm run start:ui',
|
||||||
|
url: 'http://localhost:8080',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443',
|
||||||
|
reuseExistingServer: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'node ./server/index.js',
|
||||||
|
port: 3001,
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
@@ -243,6 +243,7 @@ function App(): ReactElement {
|
|||||||
{proverMessages.map((m, index) => (
|
{proverMessages.map((m, index) => (
|
||||||
<span
|
<span
|
||||||
key={index}
|
key={index}
|
||||||
|
data-testid="prover-data"
|
||||||
className="px-3 py-1 text-slate-600 break-all"
|
className="px-3 py-1 text-slate-600 break-all"
|
||||||
>
|
>
|
||||||
{m}
|
{m}
|
||||||
@@ -257,6 +258,7 @@ function App(): ReactElement {
|
|||||||
{verifierMessages.map((m, index) => (
|
{verifierMessages.map((m, index) => (
|
||||||
<span
|
<span
|
||||||
key={index}
|
key={index}
|
||||||
|
data-testid="verifier-data"
|
||||||
className="px-3 py-1 text-slate-600 break-all"
|
className="px-3 py-1 text-slate-600 break-all"
|
||||||
>
|
>
|
||||||
{m}
|
{m}
|
||||||
@@ -271,7 +273,7 @@ function App(): ReactElement {
|
|||||||
disabled={!ready || started}
|
disabled={!ready || started}
|
||||||
onClick={start}
|
onClick={start}
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div data-testid="start" className="flex items-center">
|
||||||
{ready && !started ? (
|
{ready && !started ? (
|
||||||
<>Start Demo</>
|
<>Start Demo</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
24
demo/web-to-web-p2p/tests/demo-flow.spec.ts
Normal file
24
demo/web-to-web-p2p/tests/demo-flow.spec.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('has title', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
await expect(page).toHaveTitle(/Web-to-Web P2P Demo/)
|
||||||
|
});
|
||||||
|
|
||||||
|
test('run web-to-web p2p demo', async ({ page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
await page.getByTestId('start').click();
|
||||||
|
|
||||||
|
await expect(page.getByTestId('start')).toContainText('Start Demo', { timeout: 60000 });
|
||||||
|
|
||||||
|
const proverMessages = await page.getByTestId('prover-data').allTextContents();
|
||||||
|
expect(proverMessages.some(text => text.includes('Transcript received'))).toBe(true);
|
||||||
|
// console.log('Verifier Messages:', proverMessages);
|
||||||
|
expect(proverMessages.some(text => text.includes('"name": "John Doe",'))).toBe(true);
|
||||||
|
expect(proverMessages.some(text => text.includes('"address": {'))).toBe(true);
|
||||||
|
|
||||||
|
const verifierMessages = await page.getByTestId('verifier-data').allTextContents();
|
||||||
|
expect(verifierMessages.some(text => text.includes('Verification completed'))).toBe(true);
|
||||||
|
expect(verifierMessages.some(text => text.includes('***"name": "John Doe"*************************"street": "123 Elm Street"***'))).toBe(true);
|
||||||
|
});
|
||||||
1237
package-lock.json
generated
1237
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -23,13 +23,12 @@
|
|||||||
"lint:eslint": "eslint . --fix",
|
"lint:eslint": "eslint . --fix",
|
||||||
"lint:tsc": "tsc --noEmit",
|
"lint:tsc": "tsc --noEmit",
|
||||||
"lint": "concurrently npm:lint:tsc npm:lint:eslint",
|
"lint": "concurrently npm:lint:tsc npm:lint:eslint",
|
||||||
"run:spec": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha -r ts-node/register 'test/specs/*.ts'",
|
"test": "playwright test",
|
||||||
"run:e2e": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha -r ts-node/register 'test/testRunner.ts'",
|
|
||||||
"test": "npm run build:test && npm run run:e2e",
|
|
||||||
"notary": "docker run --platform=linux/amd64 -p 7047:7047 --rm ghcr.io/tlsnotary/tlsn/notary-server:v0.1.0-alpha.10 notary-server --tls-enabled=false"
|
"notary": "docker run --platform=linux/amd64 -p 7047:7047 --rm ghcr.io/tlsnotary/tlsn/notary-server:v0.1.0-alpha.10 notary-server --tls-enabled=false"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^10.0.6",
|
"@playwright/test": "^1.52.0",
|
||||||
|
"@types/node": "^22.15.18",
|
||||||
"@types/serve-handler": "^6.1.4",
|
"@types/serve-handler": "^6.1.4",
|
||||||
"browserify": "^17.0.0",
|
"browserify": "^17.0.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
@@ -43,20 +42,17 @@
|
|||||||
"eslint-plugin-prettier": "^5.0.0",
|
"eslint-plugin-prettier": "^5.0.0",
|
||||||
"file-loader": "^5.0.2",
|
"file-loader": "^5.0.2",
|
||||||
"html-webpack-plugin": "~5.3.2",
|
"html-webpack-plugin": "~5.3.2",
|
||||||
"https-browserify": "^1.0.0",
|
|
||||||
"http-parser-js": "^0.5.9",
|
"http-parser-js": "^0.5.9",
|
||||||
|
"https-browserify": "^1.0.0",
|
||||||
"image-webpack-loader": "^6.0.0",
|
"image-webpack-loader": "^6.0.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"mocha": "^10.2.0",
|
|
||||||
"node-loader": "^0.6.0",
|
"node-loader": "^0.6.0",
|
||||||
"prettier": "^3.0.2",
|
"prettier": "^3.0.2",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"puppeteer": "^24.1.0",
|
|
||||||
"serve": "14.2.1",
|
"serve": "14.2.1",
|
||||||
"serve-handler": "^6.1.5",
|
"serve-handler": "^6.1.5",
|
||||||
"stream-browserify": "^3.0.0",
|
"stream-browserify": "^3.0.0",
|
||||||
"ts-loader": "^6.2.1",
|
"ts-loader": "^6.2.1",
|
||||||
"ts-mocha": "^10.0.0",
|
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"typescript-eslint": "^7.4.0",
|
"typescript-eslint": "^7.4.0",
|
||||||
|
|||||||
26
playwright-test/full-integration.spec.ts
Normal file
26
playwright-test/full-integration.spec.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('full-integration', async ({ page }) => {
|
||||||
|
// log browser console messages
|
||||||
|
page.on('console', (msg) => {
|
||||||
|
console.log(`[BROWSER ${msg.type().toUpperCase()}] ${msg.text()}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto('/full-integration');
|
||||||
|
|
||||||
|
await expect(page.getByTestId('full-integration')).toHaveText(/\{.*\}/s, { timeout: 60000 });
|
||||||
|
|
||||||
|
const json = await page.getByTestId('full-integration').innerText();
|
||||||
|
const { sent, recv, server_name, version, meta } = JSON.parse(json);
|
||||||
|
|
||||||
|
expect(version).toBe('0.1.0-alpha.10');
|
||||||
|
expect(new URL(meta.notaryUrl!).protocol === 'http:');
|
||||||
|
expect(server_name).toBe('raw.githubusercontent.com');
|
||||||
|
|
||||||
|
expect(sent).toContain('host: raw.githubusercontent.com');
|
||||||
|
expect(sent).not.toContain('secret: test_secret');
|
||||||
|
expect(recv).toContain('"id": 1234567890');
|
||||||
|
expect(recv).toContain('"city": "Anytown"');
|
||||||
|
expect(recv).toContain('"postalCode": "12345"');
|
||||||
|
|
||||||
|
});
|
||||||
20
playwright-test/simple-verify.spec.ts
Normal file
20
playwright-test/simple-verify.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test('simple verify', async ({ page }) => {
|
||||||
|
// log browser console messages
|
||||||
|
page.on('console', (msg) => {
|
||||||
|
console.log(`[BROWSER ${msg.type().toUpperCase()}] ${msg.text()}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto('/simple-verify');
|
||||||
|
|
||||||
|
await expect(page.getByTestId('simple-verify')).toHaveText(/\{.*\}/s);
|
||||||
|
|
||||||
|
const json = await page.getByTestId('simple-verify').innerText();
|
||||||
|
const { sent, recv } = JSON.parse(json);
|
||||||
|
|
||||||
|
expect(sent).toContain('host: raw.githubusercontent.com');
|
||||||
|
expect(recv).toContain('"name": "John Doe"');
|
||||||
|
expect(recv).toContain('"city": "Anytown"');
|
||||||
|
expect(recv).toContain('"id": **********,');
|
||||||
|
});
|
||||||
85
playwright.config.ts
Normal file
85
playwright.config.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read environment variables from file.
|
||||||
|
* https://github.com/motdotla/dotenv
|
||||||
|
*/
|
||||||
|
// import dotenv from 'dotenv';
|
||||||
|
// import path from 'path';
|
||||||
|
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './playwright-test',
|
||||||
|
/* Run tests in files in parallel */
|
||||||
|
fullyParallel: true,
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
/* Retry on CI only */
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
baseURL: 'http://localhost:3001',
|
||||||
|
|
||||||
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
use: { ...devices['Desktop Chrome'] },
|
||||||
|
},
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'firefox',
|
||||||
|
// use: { ...devices['Desktop Firefox'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: 'webkit',
|
||||||
|
// use: { ...devices['Desktop Safari'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against mobile viewports. */
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Chrome',
|
||||||
|
// use: { ...devices['Pixel 5'] },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Mobile Safari',
|
||||||
|
// use: { ...devices['iPhone 12'] },
|
||||||
|
// },
|
||||||
|
|
||||||
|
/* Test against branded browsers. */
|
||||||
|
// {
|
||||||
|
// name: 'Microsoft Edge',
|
||||||
|
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'Google Chrome',
|
||||||
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
|
||||||
|
/* Run your local dev server before starting the tests */
|
||||||
|
webServer: [
|
||||||
|
{
|
||||||
|
command: 'npm run build:test && npm run serve:test',
|
||||||
|
url: 'http://localhost:3001',
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443',
|
||||||
|
reuseExistingServer: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
});
|
||||||
111
readme.md
111
readme.md
@@ -1,43 +1,42 @@
|
|||||||
![MIT licensed][mit-badge]
|
![MIT licensed][mit-badge]
|
||||||
![Apache licensed][apache-badge]
|
![Apache licensed][apache-badge]
|
||||||
|
|
||||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||||
[apache-badge]: https://img.shields.io/github/license/saltstack/salt
|
[apache-badge]: https://img.shields.io/github/license/saltstack/salt
|
||||||
|
|
||||||
# tlsn-js
|
# tlsn-js
|
||||||
|
|
||||||
NPM Modules for proving and verifying using TLSNotary in the browser.
|
NPM modules for proving and verifying using TLSNotary in the browser.
|
||||||
|
|
||||||
The prover requires a [notary-server](https://github.com/tlsnotary/notary-server) and a websocket proxy.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> The primary purpose of `tlsn-js` is to support the development of the [TLSNotary browser extension](https://github.com/tlsnotary/tlsn-extension/).
|
> `tlsn-js` is developed specifically for **browser environments** and does **not** work in Node.js.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The primary goal of `tlsn-js` is to support the development of the [TLSNotary browser extension](https://github.com/tlsnotary/tlsn-extension/).
|
||||||
> **Please do not treat this as a public API (yet).**
|
> **Please do not treat this as a public API (yet).**
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> `tlsn-js` is developed for the usage of TLSNotary **in the Browser**. This module does not work in `nodejs`.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
This repository is licensed under either of
|
|
||||||
|
This repository is licensed under either:
|
||||||
|
|
||||||
- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
- [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
- [MIT license](http://opensource.org/licenses/MIT)
|
- [MIT License](http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
at your option.
|
...at your option.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
`tlsn-js` can be used in many different modes, depending on your use case.
|
`tlsn-js` can be used in several modes depending on your use case.
|
||||||
|
|
||||||
The `./demo` folder contains three demos of `tlsn-js`:
|
The `./demo` folder contains three demos:
|
||||||
|
|
||||||
* `react-ts-webpack`: create an attestation with a Notary and render the result.
|
- `react-ts-webpack`: Create an attestation with a Notary and render the result.
|
||||||
* `interactive-demo`: prove data interactively to a Verifier.
|
- `interactive-demo`: Prove data interactively to a Verifier.
|
||||||
* `web-to-web-p2p`: prove data between two peers, in the browser.
|
- `web-to-web-p2p`: Prove data between two browser peers.
|
||||||
|
|
||||||
## Running a local websocket proxy
|
## Running a Local WebSocket Proxy
|
||||||
|
|
||||||
In the demos, we attest data from `https://raw.githubusercontent.com`. Because the browser does not allow for TCP connections, you need to set up a websocket proxy:
|
In the demos, we attest data from `https://raw.githubusercontent.com`. Since browsers do not support raw TCP connections, a WebSocket proxy is required:
|
||||||
|
|
||||||
1. Install [wstcp](https://github.com/sile/wstcp):
|
1. Install [wstcp](https://github.com/sile/wstcp):
|
||||||
|
|
||||||
@@ -47,33 +46,42 @@ In the demos, we attest data from `https://raw.githubusercontent.com`. Because t
|
|||||||
| brew | `brew install wstcp` |
|
| brew | `brew install wstcp` |
|
||||||
| source | https://github.com/sile/wstcp |
|
| source | https://github.com/sile/wstcp |
|
||||||
|
|
||||||
2. Run a websocket proxy for `https://raw.githubusercontent.com`:
|
2. Run a WebSocket proxy for `https://raw.githubusercontent.com`:
|
||||||
```sh
|
|
||||||
wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443
|
```sh
|
||||||
```
|
wstcp --bind-addr 127.0.0.1:55688 raw.githubusercontent.com:443
|
||||||
|
```
|
||||||
|
|
||||||
## Install as NPM Package
|
## Install as NPM Package
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install tlsn-js
|
npm install tlsn-js
|
||||||
```
|
```
|
||||||
|
|
||||||
# Development
|
## Development
|
||||||
|
|
||||||
This library is a JS wrapper for `tlsn-wasm`.
|
This library wraps the `tlsn-wasm` module.
|
||||||
|
|
||||||
To work on `tlsn-wasm` and `tlsn-js` at the same time, replace the "tlsn-wasm" dependency in `package.json` with:
|
To work on both `tlsn-wasm` and `tlsn-js` locally, update `package.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"tlsn-wasm": "./tlsn-wasm/pkg"
|
||||||
```
|
```
|
||||||
"tlsn-wasm": "./tlsn-wasm/pkg"
|
|
||||||
```
|
|
||||||
and run `npm run build:wasm` to build `tlsn-wasm` locally.
|
|
||||||
|
|
||||||
Next, run:
|
Then build `tlsn-wasm`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run build:wasm
|
||||||
|
```
|
||||||
|
|
||||||
|
Next:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install
|
npm install
|
||||||
npm run test
|
npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: if you want to switch back to a build with the version from npm, make sure to reset/remove `package-lock.json`, or it will keep using the local link.
|
> ℹ️ To switch back to the npm-published version of `tlsn-wasm`, delete or reset `package-lock.json` to remove the local path reference.
|
||||||
|
|
||||||
## Build for NPM
|
## Build for NPM
|
||||||
|
|
||||||
@@ -82,9 +90,42 @@ npm install
|
|||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding a new test
|
## Testing
|
||||||
1. Create a new `new-test.spec.ts` file in the `test/` directory.
|
|
||||||
2. Add your spec file to the entry object in `webpack.web.dev.config.js`.
|
|
||||||
3. Add a new `div` block to `test/test.ejs` like this: `<div>Testing "new-test":<div id="new-test"></div></div>`. The `div` id must be the same as the filename.
|
|
||||||
|
|
||||||
|
Testing is slightly complex due to the need for browser-based workers.
|
||||||
|
|
||||||
|
- Tests live in the `test/` directory.
|
||||||
|
- The `tests/` directory contains a Playwright test runner that opens a Chromium browser and runs the actual test page.
|
||||||
|
|
||||||
|
Some tests require a running Notary. You can start one via Docker:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run notary
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding a New `tlsn-js` Test
|
||||||
|
|
||||||
|
1. Create a `new-test.spec.ts` file in the `test/` directory.
|
||||||
|
2. Add your spec file to the `entry` object in `webpack.web.dev.config.js`.
|
||||||
|
3. Create a corresponding `new-test.spec.ts` file in the `playwright-test/` directory.
|
||||||
|
|
||||||
|
4. Add an `expect()` call for it in `tests/test.spec.ts`.
|
||||||
|
|
||||||
|
### Testing the Demos
|
||||||
|
|
||||||
|
Playwright is also used to test the demos.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
- View tests in the browser:
|
||||||
|
```sh
|
||||||
|
npx playwright test --ui
|
||||||
|
```
|
||||||
|
|
||||||
|
- Debug tests:
|
||||||
|
```sh
|
||||||
|
npx playwright test --debug
|
||||||
|
```
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
Transcript,
|
Transcript,
|
||||||
} from '../../src/lib';
|
} from '../../src/lib';
|
||||||
import * as Comlink from 'comlink';
|
import * as Comlink from 'comlink';
|
||||||
import { assert } from '../utils';
|
|
||||||
import { HTTPParser } from 'http-parser-js';
|
import { HTTPParser } from 'http-parser-js';
|
||||||
|
|
||||||
const { init, Prover, Presentation }: any = Comlink.wrap(
|
const { init, Prover, Presentation }: any = Comlink.wrap(
|
||||||
@@ -89,8 +88,7 @@ const { init, Prover, Presentation }: any = Comlink.wrap(
|
|||||||
console.log('presentation:', await presentation.serialize());
|
console.log('presentation:', await presentation.serialize());
|
||||||
console.timeEnd('prove');
|
console.timeEnd('prove');
|
||||||
const json = await presentation.json();
|
const json = await presentation.json();
|
||||||
assert(json.version === '0.1.0-alpha.10');
|
|
||||||
assert(new URL(json.meta.notaryUrl!).protocol === 'http:');
|
|
||||||
|
|
||||||
console.time('verify');
|
console.time('verify');
|
||||||
const { transcript: partialTranscript, server_name } =
|
const { transcript: partialTranscript, server_name } =
|
||||||
@@ -109,19 +107,17 @@ const { init, Prover, Presentation }: any = Comlink.wrap(
|
|||||||
console.log("Sent:", sentStr);
|
console.log("Sent:", sentStr);
|
||||||
console.log("Received:", recvStr);
|
console.log("Received:", recvStr);
|
||||||
|
|
||||||
assert(sentStr.includes('host: raw.githubusercontent.com'));
|
|
||||||
assert(!sentStr.includes('secret: test_secret'));
|
|
||||||
assert(recvStr.includes('"id": 1234567890'));
|
|
||||||
assert(recvStr.includes('"city": "Anytown"'));
|
|
||||||
assert(recvStr.includes('"postalCode": "12345"'));
|
|
||||||
assert(server_name === 'raw.githubusercontent.com');
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
document.getElementById('full-integration').textContent = 'OK';
|
document.getElementById('full-integration').textContent = JSON.stringify({
|
||||||
|
sent: sentStr,
|
||||||
|
recv: recvStr,
|
||||||
|
version: json.version,
|
||||||
|
meta: json.meta,
|
||||||
|
server_name
|
||||||
|
}, null, 2);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('caught error from wasm');
|
console.log('caught error from wasm');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
document.getElementById('full-integration').textContent = err.message;
|
document.getElementById('full-integration').textContent = err.message;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { Presentation as _Presentation } from '../../src/lib';
|
|||||||
// import { assert } from '../utils';
|
// import { assert } from '../utils';
|
||||||
import * as Comlink from 'comlink';
|
import * as Comlink from 'comlink';
|
||||||
import { Transcript } from '../../src/lib';
|
import { Transcript } from '../../src/lib';
|
||||||
import { assert } from '../utils';
|
|
||||||
|
|
||||||
const { init, Presentation }: any = Comlink.wrap(
|
const { init, Presentation }: any = Comlink.wrap(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -26,16 +25,11 @@ const { init, Presentation }: any = Comlink.wrap(
|
|||||||
const sent = transcript.sent();
|
const sent = transcript.sent();
|
||||||
const recv = transcript.recv();
|
const recv = transcript.recv();
|
||||||
|
|
||||||
console.log('sent', sent);
|
|
||||||
console.log('recv', recv);
|
|
||||||
|
|
||||||
assert(sent.includes('host: raw.githubusercontent.com'));
|
|
||||||
|
|
||||||
assert(recv.includes('"name": "John Doe"'));
|
|
||||||
assert(recv.includes('"city": "Anytown"'));
|
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
document.getElementById('simple-verify').textContent = 'OK';
|
document.getElementById('simple-verify').textContent = JSON.stringify({
|
||||||
|
sent,
|
||||||
|
recv
|
||||||
|
}, null, 2);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('caught error from wasm');
|
console.log('caught error from wasm');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
import { describe, it } from 'mocha';
|
|
||||||
import * as assert from 'assert';
|
|
||||||
import { Transcript } from '../../src/transcript';
|
|
||||||
|
|
||||||
describe('Transcript parsing', () => {
|
|
||||||
it('should parse transcript correctly', async () => {
|
|
||||||
const transcript = new Transcript({ sent: swapiSent, recv: swapiRecv });
|
|
||||||
assert.strictEqual(
|
|
||||||
Buffer.from(transcript.raw.sent).toString('utf-8'),
|
|
||||||
'GET https://swapi.dev/api/people/1 HTTP/1.1\r\nconnection: close\r\ncontent-length: 25\r\ncontent-type: application/json\r\nhost: swapi.dev\r\n\r\n{"hello":"world","one":1}',
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
Buffer.from(transcript.raw.recv).toString('utf-8'),
|
|
||||||
'HTTP/1.1 200 OK\r\nServer: nginx/1.16.1\r\nDate: Fri, 07 Feb 2025 07:37:11 GMT\r\nContent-Type: application/json\r\nTransfer-Encoding: chunked\r\nConnection: close\r\nVary: Accept, Cookie\r\nX-Frame-Options: SAMEORIGIN\r\nETag: \"ee398610435c328f4d0a4e1b0d2f7bbc\"\r\nAllow: GET, HEAD, OPTIONS\r\nStrict-Transport-Security: max-age=15768000\r\n\r\n287\r\n{\"name\":\"Luke Skywalker\",\"height\":\"172\",\"mass\":\"77\",\"hair_color\":\"blond\",\"skin_color\":\"fair\",\"eye_color\":\"blue\",\"birth_year\":\"19BBY\",\"gender\":\"male\",\"homeworld\":\"https://swapi.dev/api/planets/1/\",\"films\":[\"https://swapi.dev/api/films/1/\",\"https://swapi.dev/api/films/2/\",\"https://swapi.dev/api/films/3/\",\"https://swapi.dev/api/films/6/\"],\"species\":[],\"vehicles\":[\"https://swapi.dev/api/vehicles/14/\",\"https://swapi.dev/api/vehicles/30/\"],\"starships\":[\"https://swapi.dev/api/starships/12/\",\"https://swapi.dev/api/starships/22/\"],\"created\":\"2014-12-09T13:50:51.644000Z\",\"edited\":\"2014-12-20T21:17:56.891000Z\",\"url\":\"https://swapi.dev/api/people/1/\"}\r\n0\r\n\r\n',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const swapiRecv = [
|
|
||||||
72, 84, 84, 80, 47, 49, 46, 49, 32, 50, 48, 48, 32, 79, 75, 13, 10, 83, 101,
|
|
||||||
114, 118, 101, 114, 58, 32, 110, 103, 105, 110, 120, 47, 49, 46, 49, 54, 46,
|
|
||||||
49, 13, 10, 68, 97, 116, 101, 58, 32, 70, 114, 105, 44, 32, 48, 55, 32, 70,
|
|
||||||
101, 98, 32, 50, 48, 50, 53, 32, 48, 55, 58, 51, 55, 58, 49, 49, 32, 71, 77,
|
|
||||||
84, 13, 10, 67, 111, 110, 116, 101, 110, 116, 45, 84, 121, 112, 101, 58, 32,
|
|
||||||
97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47, 106, 115, 111, 110,
|
|
||||||
13, 10, 84, 114, 97, 110, 115, 102, 101, 114, 45, 69, 110, 99, 111, 100, 105,
|
|
||||||
110, 103, 58, 32, 99, 104, 117, 110, 107, 101, 100, 13, 10, 67, 111, 110, 110,
|
|
||||||
101, 99, 116, 105, 111, 110, 58, 32, 99, 108, 111, 115, 101, 13, 10, 86, 97,
|
|
||||||
114, 121, 58, 32, 65, 99, 99, 101, 112, 116, 44, 32, 67, 111, 111, 107, 105,
|
|
||||||
101, 13, 10, 88, 45, 70, 114, 97, 109, 101, 45, 79, 112, 116, 105, 111, 110,
|
|
||||||
115, 58, 32, 83, 65, 77, 69, 79, 82, 73, 71, 73, 78, 13, 10, 69, 84, 97, 103,
|
|
||||||
58, 32, 34, 101, 101, 51, 57, 56, 54, 49, 48, 52, 51, 53, 99, 51, 50, 56, 102,
|
|
||||||
52, 100, 48, 97, 52, 101, 49, 98, 48, 100, 50, 102, 55, 98, 98, 99, 34, 13,
|
|
||||||
10, 65, 108, 108, 111, 119, 58, 32, 71, 69, 84, 44, 32, 72, 69, 65, 68, 44,
|
|
||||||
32, 79, 80, 84, 73, 79, 78, 83, 13, 10, 83, 116, 114, 105, 99, 116, 45, 84,
|
|
||||||
114, 97, 110, 115, 112, 111, 114, 116, 45, 83, 101, 99, 117, 114, 105, 116,
|
|
||||||
121, 58, 32, 109, 97, 120, 45, 97, 103, 101, 61, 49, 53, 55, 54, 56, 48, 48,
|
|
||||||
48, 13, 10, 13, 10, 50, 56, 55, 13, 10, 123, 34, 110, 97, 109, 101, 34, 58,
|
|
||||||
34, 76, 117, 107, 101, 32, 83, 107, 121, 119, 97, 108, 107, 101, 114, 34, 44,
|
|
||||||
34, 104, 101, 105, 103, 104, 116, 34, 58, 34, 49, 55, 50, 34, 44, 34, 109, 97,
|
|
||||||
115, 115, 34, 58, 34, 55, 55, 34, 44, 34, 104, 97, 105, 114, 95, 99, 111, 108,
|
|
||||||
111, 114, 34, 58, 34, 98, 108, 111, 110, 100, 34, 44, 34, 115, 107, 105, 110,
|
|
||||||
95, 99, 111, 108, 111, 114, 34, 58, 34, 102, 97, 105, 114, 34, 44, 34, 101,
|
|
||||||
121, 101, 95, 99, 111, 108, 111, 114, 34, 58, 34, 98, 108, 117, 101, 34, 44,
|
|
||||||
34, 98, 105, 114, 116, 104, 95, 121, 101, 97, 114, 34, 58, 34, 49, 57, 66, 66,
|
|
||||||
89, 34, 44, 34, 103, 101, 110, 100, 101, 114, 34, 58, 34, 109, 97, 108, 101,
|
|
||||||
34, 44, 34, 104, 111, 109, 101, 119, 111, 114, 108, 100, 34, 58, 34, 104, 116,
|
|
||||||
116, 112, 115, 58, 47, 47, 115, 119, 97, 112, 105, 46, 100, 101, 118, 47, 97,
|
|
||||||
112, 105, 47, 112, 108, 97, 110, 101, 116, 115, 47, 49, 47, 34, 44, 34, 102,
|
|
||||||
105, 108, 109, 115, 34, 58, 91, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115,
|
|
||||||
119, 97, 112, 105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 102, 105, 108,
|
|
||||||
109, 115, 47, 49, 47, 34, 44, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115,
|
|
||||||
119, 97, 112, 105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 102, 105, 108,
|
|
||||||
109, 115, 47, 50, 47, 34, 44, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115,
|
|
||||||
119, 97, 112, 105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 102, 105, 108,
|
|
||||||
109, 115, 47, 51, 47, 34, 44, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115,
|
|
||||||
119, 97, 112, 105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 102, 105, 108,
|
|
||||||
109, 115, 47, 54, 47, 34, 93, 44, 34, 115, 112, 101, 99, 105, 101, 115, 34,
|
|
||||||
58, 91, 93, 44, 34, 118, 101, 104, 105, 99, 108, 101, 115, 34, 58, 91, 34,
|
|
||||||
104, 116, 116, 112, 115, 58, 47, 47, 115, 119, 97, 112, 105, 46, 100, 101,
|
|
||||||
118, 47, 97, 112, 105, 47, 118, 101, 104, 105, 99, 108, 101, 115, 47, 49, 52,
|
|
||||||
47, 34, 44, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115, 119, 97, 112, 105,
|
|
||||||
46, 100, 101, 118, 47, 97, 112, 105, 47, 118, 101, 104, 105, 99, 108, 101,
|
|
||||||
115, 47, 51, 48, 47, 34, 93, 44, 34, 115, 116, 97, 114, 115, 104, 105, 112,
|
|
||||||
115, 34, 58, 91, 34, 104, 116, 116, 112, 115, 58, 47, 47, 115, 119, 97, 112,
|
|
||||||
105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 115, 116, 97, 114, 115, 104,
|
|
||||||
105, 112, 115, 47, 49, 50, 47, 34, 44, 34, 104, 116, 116, 112, 115, 58, 47,
|
|
||||||
47, 115, 119, 97, 112, 105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 115, 116,
|
|
||||||
97, 114, 115, 104, 105, 112, 115, 47, 50, 50, 47, 34, 93, 44, 34, 99, 114,
|
|
||||||
101, 97, 116, 101, 100, 34, 58, 34, 50, 48, 49, 52, 45, 49, 50, 45, 48, 57,
|
|
||||||
84, 49, 51, 58, 53, 48, 58, 53, 49, 46, 54, 52, 52, 48, 48, 48, 90, 34, 44,
|
|
||||||
34, 101, 100, 105, 116, 101, 100, 34, 58, 34, 50, 48, 49, 52, 45, 49, 50, 45,
|
|
||||||
50, 48, 84, 50, 49, 58, 49, 55, 58, 53, 54, 46, 56, 57, 49, 48, 48, 48, 90,
|
|
||||||
34, 44, 34, 117, 114, 108, 34, 58, 34, 104, 116, 116, 112, 115, 58, 47, 47,
|
|
||||||
115, 119, 97, 112, 105, 46, 100, 101, 118, 47, 97, 112, 105, 47, 112, 101,
|
|
||||||
111, 112, 108, 101, 47, 49, 47, 34, 125, 13, 10, 48, 13, 10, 13, 10,
|
|
||||||
];
|
|
||||||
|
|
||||||
const swapiSent = [
|
|
||||||
71, 69, 84, 32, 104, 116, 116, 112, 115, 58, 47, 47, 115, 119, 97, 112, 105,
|
|
||||||
46, 100, 101, 118, 47, 97, 112, 105, 47, 112, 101, 111, 112, 108, 101, 47, 49,
|
|
||||||
32, 72, 84, 84, 80, 47, 49, 46, 49, 13, 10, 99, 111, 110, 110, 101, 99, 116,
|
|
||||||
105, 111, 110, 58, 32, 99, 108, 111, 115, 101, 13, 10, 99, 111, 110, 116, 101,
|
|
||||||
110, 116, 45, 108, 101, 110, 103, 116, 104, 58, 32, 50, 53, 13, 10, 99, 111,
|
|
||||||
110, 116, 101, 110, 116, 45, 116, 121, 112, 101, 58, 32, 97, 112, 112, 108,
|
|
||||||
105, 99, 97, 116, 105, 111, 110, 47, 106, 115, 111, 110, 13, 10, 104, 111,
|
|
||||||
115, 116, 58, 32, 115, 119, 97, 112, 105, 46, 100, 101, 118, 13, 10, 13, 10,
|
|
||||||
123, 34, 104, 101, 108, 108, 111, 34, 58, 34, 119, 111, 114, 108, 100, 34, 44,
|
|
||||||
34, 111, 110, 101, 34, 58, 49, 125,
|
|
||||||
];
|
|
||||||
@@ -5,19 +5,21 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="manifest" href="/manifest.json">
|
<link rel="manifest" href="/manifest.json">
|
||||||
<title>tlsn-js development</title>
|
<title>
|
||||||
|
Testing <%= htmlWebpackPlugin.options.testName || 'test' %>
|
||||||
|
</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
global = globalThis //<- this should be enough
|
global = globalThis //<- this should be enough
|
||||||
</script>
|
</script>
|
||||||
<div>Testing "full-integration":
|
<h1>Testing "<%= htmlWebpackPlugin.options.testName || 'unknown' %>":</h1>
|
||||||
<div id="full-integration"></div>
|
<pre>
|
||||||
</div>
|
<div id="<%= htmlWebpackPlugin.options.testName || 'test' %>"
|
||||||
<div>Testing "simple-verify":
|
data-testid="<%= htmlWebpackPlugin.options.testName || 'test' %>">
|
||||||
<div id="simple-verify"></div>
|
</div>
|
||||||
</div>
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
import puppeteer, { Browser, LaunchOptions, Page } from 'puppeteer';
|
|
||||||
import { describe, it, before, after } from 'mocha';
|
|
||||||
const assert = require('assert');
|
|
||||||
import { exec, ChildProcess } from 'node:child_process';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
const timeout = 300000;
|
|
||||||
|
|
||||||
// puppeteer options
|
|
||||||
let opts: LaunchOptions = {
|
|
||||||
headless: !!process.env.HEADLESS ? true : false,
|
|
||||||
slowMo: 100,
|
|
||||||
timeout: timeout,
|
|
||||||
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.CHROME_PATH) {
|
|
||||||
opts = {
|
|
||||||
...opts,
|
|
||||||
executablePath: process.env.CHROME_PATH,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let browser: Browser;
|
|
||||||
let page: Page;
|
|
||||||
let server: ChildProcess;
|
|
||||||
|
|
||||||
const waitForNotaryServer = async () => {
|
|
||||||
// wait for the notary server to be ready
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
const response = await fetch('http://127.0.0.1:7047/info');
|
|
||||||
if (response.ok) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Waiting for local notary server...', error);
|
|
||||||
}
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// expose variables
|
|
||||||
before(async function () {
|
|
||||||
server = exec('serve --config ../serve.json ./test-build -l 3001');
|
|
||||||
|
|
||||||
await waitForNotaryServer();
|
|
||||||
browser = await puppeteer.launch(opts);
|
|
||||||
page = await browser.newPage();
|
|
||||||
|
|
||||||
// log browser console messages
|
|
||||||
page.on('console', (msg) => {
|
|
||||||
console.log(`[BROWSER ${msg.type().toUpperCase()}] ${msg.text()}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
await page.goto('http://127.0.0.1:3001');
|
|
||||||
});
|
|
||||||
|
|
||||||
// close browser and reset global variables
|
|
||||||
after(async function () {
|
|
||||||
console.log('Cleaning up:');
|
|
||||||
|
|
||||||
try {
|
|
||||||
server.kill();
|
|
||||||
console.log('* Stopped Test Web Server ✅');
|
|
||||||
|
|
||||||
if (page) {
|
|
||||||
await page.close();
|
|
||||||
}
|
|
||||||
if (browser) {
|
|
||||||
await browser.close();
|
|
||||||
const childProcess = browser.process();
|
|
||||||
if (childProcess) {
|
|
||||||
childProcess.kill(9);
|
|
||||||
}
|
|
||||||
console.log('* Closed browser ✅');
|
|
||||||
|
|
||||||
const tests = this.test?.parent?.suites.flatMap((suite) => suite.tests);
|
|
||||||
const failed = tests!.some((test) => test.state === 'failed');
|
|
||||||
|
|
||||||
console.log('tests', tests);
|
|
||||||
console.log('failed', failed);
|
|
||||||
process.exit(failed ? 1 : 0);
|
|
||||||
}
|
|
||||||
process.exit(1);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('tlsn-js test suite', function () {
|
|
||||||
fs.readdirSync(path.join(__dirname, 'e2e')).forEach((file) => {
|
|
||||||
const [id] = file.split('.');
|
|
||||||
it(`Test ID: ${id}`, async function () {
|
|
||||||
const content = await check(id);
|
|
||||||
assert.strictEqual(
|
|
||||||
content,
|
|
||||||
'OK',
|
|
||||||
`Test ID: ${id} - Expected 'OK' but got '${content}'`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
async function check(testId: string): Promise<string> {
|
|
||||||
const startTime = Date.now();
|
|
||||||
const attemptFetchContent = async (): Promise<string> => {
|
|
||||||
const content = await page.$eval(
|
|
||||||
`#${testId}`,
|
|
||||||
(el: any) => el.textContent || '',
|
|
||||||
);
|
|
||||||
if (content) return content;
|
|
||||||
const elapsedTime = Date.now() - startTime;
|
|
||||||
if (elapsedTime >= timeout) {
|
|
||||||
throw new Error(
|
|
||||||
`Timeout: Failed to retrieve content for '#${testId}' within ${timeout} ms.`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
||||||
return attemptFetchContent();
|
|
||||||
};
|
|
||||||
return attemptFetchContent();
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export function assert(expr: any, msg = 'unknown assertion error') {
|
|
||||||
if (!Boolean(expr)) throw new Error(msg);
|
|
||||||
}
|
|
||||||
@@ -33,14 +33,17 @@ const rules = [
|
|||||||
|
|
||||||
const rendererRules = [];
|
const rendererRules = [];
|
||||||
|
|
||||||
|
const entry = {
|
||||||
|
'full-integration': path.join(__dirname, 'test', 'e2e', 'full-integration.spec.ts'),
|
||||||
|
'simple-verify': path.join(__dirname, 'test', 'e2e', 'simple-verify.spec.ts'),
|
||||||
|
// add more entries as needed
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
{
|
{
|
||||||
target: 'web',
|
target: 'web',
|
||||||
mode: isProd ? 'production' : 'development',
|
mode: isProd ? 'production' : 'development',
|
||||||
entry: {
|
entry,
|
||||||
'full-integration.spec': path.join(__dirname, 'test', 'e2e', 'full-integration.spec.ts'),
|
|
||||||
'simple-verify': path.join(__dirname, 'test', 'e2e', 'simple-verify.spec.ts'),
|
|
||||||
},
|
|
||||||
output: {
|
output: {
|
||||||
path: __dirname + '/test-build',
|
path: __dirname + '/test-build',
|
||||||
publicPath: '/',
|
publicPath: '/',
|
||||||
@@ -49,25 +52,6 @@ module.exports = [
|
|||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.tsx', '.js', '.jsx', '.png', '.svg'],
|
extensions: ['.ts', '.tsx', '.js', '.jsx', '.png', '.svg'],
|
||||||
// modules: [
|
|
||||||
// path.resolve('./node_modules'),
|
|
||||||
// path.resolve(__dirname, compilerOptions.baseUrl),
|
|
||||||
// ],
|
|
||||||
// fallback: {
|
|
||||||
// browserify: require.resolve('browserify'),
|
|
||||||
// stream: require.resolve('stream-browserify'),
|
|
||||||
// path: require.resolve('path-browserify'),
|
|
||||||
// crypto: require.resolve('crypto-browserify'),
|
|
||||||
// os: require.resolve('os-browserify/browser'),
|
|
||||||
// http: require.resolve('stream-http'),
|
|
||||||
// https: require.resolve('https-browserify'),
|
|
||||||
// assert: require.resolve('assert/'),
|
|
||||||
// events: require.resolve('events/'),
|
|
||||||
// 'ansi-html-community': require.resolve('ansi-html-community'),
|
|
||||||
// 'html-entities': require.resolve('html-entities'),
|
|
||||||
// constants: false,
|
|
||||||
// fs: false,
|
|
||||||
// },
|
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [...rules, ...rendererRules],
|
rules: [...rules, ...rendererRules],
|
||||||
@@ -89,10 +73,41 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
// Generate an HTML file for each entry
|
||||||
|
...Object.keys(entry).map(
|
||||||
|
(name) =>
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './test/test.ejs',
|
||||||
|
filename: `${name}.html`,
|
||||||
|
chunks: [name],
|
||||||
|
inject: true,
|
||||||
|
testName: name,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
// Add an index page listing all test pages
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: './test/test.ejs',
|
templateContent: () => `
|
||||||
filename: `index.html`,
|
<!DOCTYPE html>
|
||||||
inject: true,
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>tlsn-js test index</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>tlsn-js test index</h1>
|
||||||
|
<ul>
|
||||||
|
${Object.keys(entry)
|
||||||
|
.map(
|
||||||
|
(name) =>
|
||||||
|
`<li><a href="${name}.html">${name}</a></li>`
|
||||||
|
)
|
||||||
|
.join('\n')}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`,
|
||||||
|
filename: 'index.html',
|
||||||
|
inject: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
stats: 'minimal',
|
stats: 'minimal',
|
||||||
|
|||||||
Reference in New Issue
Block a user