(wasm) webdriver-based tests for JS/TS apis, update README
This commit is contained in:
2
veilid-wasm/tests/.gitignore
vendored
Normal file
2
veilid-wasm/tests/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
veilid-wasm-pkg
|
1
veilid-wasm/tests/.npmrc
Normal file
1
veilid-wasm/tests/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
engine-strict=true
|
9494
veilid-wasm/tests/package-lock.json
generated
Normal file
9494
veilid-wasm/tests/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
veilid-wasm/tests/package.json
Normal file
23
veilid-wasm/tests/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "veilid-wasm-tests",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wdio/browser-runner": "^8.16.4",
|
||||
"@wdio/cli": "^8.16.4",
|
||||
"@wdio/mocha-framework": "^8.16.3",
|
||||
"@wdio/spec-reporter": "^8.16.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.2.2",
|
||||
"veilid-wasm": "file:../pkg",
|
||||
"vite-plugin-wasm": "^3.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "wdio run ./wdio.conf.ts",
|
||||
"test:headless": "WDIO_HEADLESS=true npm run test",
|
||||
"start": "tsc && npm run test:headless"
|
||||
}
|
||||
}
|
99
veilid-wasm/tests/src/VeilidTable.test.ts
Normal file
99
veilid-wasm/tests/src/VeilidTable.test.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { expect } from '@wdio/globals';
|
||||
|
||||
import {
|
||||
veilidCoreInitConfig,
|
||||
veilidCoreStartupConfig,
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { VeilidTableDB, veilidClient } from 'veilid-wasm';
|
||||
import { marshall, unmarshall } from './utils/marshalling-utils';
|
||||
|
||||
const TABLE_NAME = 'some-table';
|
||||
const TABLE_COLS = 1;
|
||||
|
||||
describe('VeilidTable', () => {
|
||||
before('veilid startup', async () => {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should open and close a table', async () => {
|
||||
const table = new VeilidTableDB(TABLE_NAME, TABLE_COLS);
|
||||
await table.openTable();
|
||||
|
||||
const keys = await table.getKeys(0);
|
||||
expect(keys.length).toBe(0);
|
||||
|
||||
table.free();
|
||||
});
|
||||
|
||||
describe('table operations', () => {
|
||||
let table: VeilidTableDB;
|
||||
|
||||
before('create table', async () => {
|
||||
table = new VeilidTableDB(TABLE_NAME, TABLE_COLS);
|
||||
await table.openTable();
|
||||
});
|
||||
|
||||
after('free table', async () => {
|
||||
table.free();
|
||||
});
|
||||
|
||||
it('should have no keys', async () => {
|
||||
const keys = await table.getKeys(0);
|
||||
expect(keys.length).toBe(0);
|
||||
});
|
||||
|
||||
describe('store/load', () => {
|
||||
const key = 'test-key with unicode 🚀';
|
||||
const value = 'test value with unicode 🚀';
|
||||
|
||||
it('should store value', async () => {
|
||||
await table.store(0, marshall(key), marshall(value));
|
||||
});
|
||||
|
||||
it('should load value', async () => {
|
||||
const storedValue = await table.load(0, marshall(key));
|
||||
expect(storedValue).toBeDefined();
|
||||
expect(unmarshall(storedValue!)).toBe(value);
|
||||
});
|
||||
|
||||
it('should have key in list of keys', async () => {
|
||||
const keys = await table.getKeys(0);
|
||||
const decodedKeys = keys.map(unmarshall);
|
||||
expect(decodedKeys).toEqual([key]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transactions', () => {
|
||||
it('should commit a transaction', async () => {
|
||||
let transaction = await table.createTransaction();
|
||||
|
||||
const key = 'tranaction-key🔥';
|
||||
const first = 'first🅱';
|
||||
const second = 'second✔';
|
||||
const third = 'third📢';
|
||||
|
||||
transaction.store(0, marshall(key), marshall(first));
|
||||
transaction.store(0, marshall(key), marshall(second));
|
||||
transaction.store(0, marshall(key), marshall(third));
|
||||
|
||||
await transaction.commit();
|
||||
|
||||
const storedValue = await table.load(0, marshall(key));
|
||||
expect(storedValue).toBeDefined();
|
||||
expect(unmarshall(storedValue!)).toBe(third);
|
||||
|
||||
transaction.free();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
45
veilid-wasm/tests/src/utils/marshalling-utils.ts
Normal file
45
veilid-wasm/tests/src/utils/marshalling-utils.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// TextEncoder/TextDecoder are used to solve for "The Unicode Problem" https://stackoverflow.com/a/30106551
|
||||
|
||||
export function marshall(data: string) {
|
||||
const byteString = bytesToString(new TextEncoder().encode(data));
|
||||
return base64UrlEncode(byteString);
|
||||
}
|
||||
|
||||
export function unmarshall(b64: string) {
|
||||
const byteString = base64UrlDecode(b64);
|
||||
return new TextDecoder().decode(stringToBytes(byteString));
|
||||
}
|
||||
|
||||
function base64UrlEncode(data: string) {
|
||||
return removeBase64Padding(btoa(data));
|
||||
}
|
||||
|
||||
function base64UrlDecode(b64: string) {
|
||||
return atob(addBase64Padding(b64));
|
||||
}
|
||||
|
||||
function removeBase64Padding(b64: string) {
|
||||
// URL encode characters, and remove `=` padding.
|
||||
return b64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
||||
}
|
||||
|
||||
function addBase64Padding(b64: string) {
|
||||
// URL decode characters
|
||||
b64 = b64.replace(/-/g, '+').replace(/_/g, '/');
|
||||
// Add base64 padding characters (`=`)
|
||||
const rem = b64.length % 4;
|
||||
if (rem === 2) {
|
||||
return `${b64}==`;
|
||||
} else if (rem === 3) {
|
||||
return `${b64}=`;
|
||||
}
|
||||
return b64;
|
||||
}
|
||||
|
||||
function stringToBytes(binString: string) {
|
||||
return Uint8Array.from(binString as any, (m) => (m as any).codePointAt(0));
|
||||
}
|
||||
|
||||
function bytesToString(bytes: Uint8Array) {
|
||||
return Array.from(bytes, (x: number) => String.fromCodePoint(x)).join('');
|
||||
}
|
140
veilid-wasm/tests/src/utils/veilid-config.ts
Normal file
140
veilid-wasm/tests/src/utils/veilid-config.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import type { VeilidWASMConfig } from 'veilid-wasm';
|
||||
|
||||
export const veilidCoreInitConfig: VeilidWASMConfig = {
|
||||
logging: {
|
||||
api: {
|
||||
enabled: true,
|
||||
level: 'Debug',
|
||||
},
|
||||
performance: {
|
||||
enabled: false,
|
||||
level: 'Info',
|
||||
logs_in_timings: false,
|
||||
logs_in_console: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const veilidCoreStartupConfig = {
|
||||
program_name: 'veilid-wasm-test',
|
||||
namespace: '',
|
||||
capabilities: {
|
||||
disable: [],
|
||||
},
|
||||
protected_store: {
|
||||
allow_insecure_fallback: true,
|
||||
always_use_insecure_storage: true,
|
||||
directory: '',
|
||||
delete: false,
|
||||
device_encryption_key_password: 'some-user-secret-value',
|
||||
// "new_device_encryption_key_password": "an-updated-user-secret-value"
|
||||
},
|
||||
table_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
block_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
network: {
|
||||
connection_initial_timeout_ms: 2000,
|
||||
connection_inactivity_timeout_ms: 60000,
|
||||
max_connections_per_ip4: 32,
|
||||
max_connections_per_ip6_prefix: 32,
|
||||
max_connections_per_ip6_prefix_size: 56,
|
||||
max_connection_frequency_per_min: 128,
|
||||
client_whitelist_timeout_ms: 300000,
|
||||
reverse_connection_receipt_time_ms: 5000,
|
||||
hole_punch_receipt_time_ms: 5000,
|
||||
network_key_password: '',
|
||||
disable_capabilites: [],
|
||||
routing_table: {
|
||||
node_id: [],
|
||||
node_id_secret: [],
|
||||
bootstrap: ['ws://bootstrap.veilid.net:5150/ws'],
|
||||
limit_over_attached: 64,
|
||||
limit_fully_attached: 32,
|
||||
limit_attached_strong: 16,
|
||||
limit_attached_good: 8,
|
||||
limit_attached_weak: 4,
|
||||
},
|
||||
rpc: {
|
||||
concurrency: 0,
|
||||
queue_size: 1024,
|
||||
max_timestamp_behind_ms: 10000,
|
||||
max_timestamp_ahead_ms: 10000,
|
||||
timeout_ms: 5000,
|
||||
max_route_hop_count: 4,
|
||||
default_route_hop_count: 1,
|
||||
},
|
||||
dht: {
|
||||
max_find_node_count: 20,
|
||||
resolve_node_timeout_ms: 10000,
|
||||
resolve_node_count: 1,
|
||||
resolve_node_fanout: 4,
|
||||
get_value_timeout_ms: 10000,
|
||||
get_value_count: 3,
|
||||
get_value_fanout: 4,
|
||||
set_value_timeout_ms: 10000,
|
||||
set_value_count: 5,
|
||||
set_value_fanout: 4,
|
||||
min_peer_count: 20,
|
||||
min_peer_refresh_time_ms: 60000,
|
||||
validate_dial_info_receipt_time_ms: 2000,
|
||||
local_subkey_cache_size: 128,
|
||||
local_max_subkey_cache_memory_mb: 256,
|
||||
remote_subkey_cache_size: 1024,
|
||||
remote_max_records: 65536,
|
||||
remote_max_subkey_cache_memory_mb: 256,
|
||||
remote_max_storage_space_mb: 0,
|
||||
},
|
||||
upnp: true,
|
||||
detect_address_changes: true,
|
||||
restricted_nat_retries: 0,
|
||||
tls: {
|
||||
certificate_path: '',
|
||||
private_key_path: '',
|
||||
connection_initial_timeout_ms: 2000,
|
||||
},
|
||||
application: {
|
||||
https: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
http: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
},
|
||||
protocol: {
|
||||
udp: {
|
||||
enabled: false,
|
||||
socket_pool_size: 0,
|
||||
listen_address: '',
|
||||
},
|
||||
tcp: {
|
||||
connect: false,
|
||||
listen: false,
|
||||
max_connections: 32,
|
||||
listen_address: '',
|
||||
},
|
||||
ws: {
|
||||
connect: true,
|
||||
listen: true,
|
||||
max_connections: 16,
|
||||
listen_address: ':5150',
|
||||
path: 'ws',
|
||||
},
|
||||
wss: {
|
||||
connect: true,
|
||||
listen: false,
|
||||
max_connections: 16,
|
||||
listen_address: '',
|
||||
path: 'ws',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
3
veilid-wasm/tests/src/utils/wait-utils.ts
Normal file
3
veilid-wasm/tests/src/utils/wait-utils.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const waitForMs = (milliseconds: number) => {
|
||||
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||
};
|
59
veilid-wasm/tests/src/veilidClient.test.ts
Normal file
59
veilid-wasm/tests/src/veilidClient.test.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { expect } from '@wdio/globals';
|
||||
|
||||
import {
|
||||
veilidCoreInitConfig,
|
||||
veilidCoreStartupConfig,
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { VeilidState, veilidClient } from 'veilid-wasm';
|
||||
import { waitForMs } from './utils/wait-utils';
|
||||
|
||||
describe('veilidClient', () => {
|
||||
before('veilid startup', async () => {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should print version', async () => {
|
||||
const version = veilidClient.versionString();
|
||||
expect(typeof version).toBe('string');
|
||||
expect(version.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should attach and detach', async () => {
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
await veilidClient.detach();
|
||||
});
|
||||
|
||||
describe('kitchen sink', () => {
|
||||
before('attach', async () => {
|
||||
await veilidClient.attach();
|
||||
await waitForMs(2000);
|
||||
});
|
||||
after('detach', () => veilidClient.detach());
|
||||
|
||||
let state: VeilidState;
|
||||
|
||||
it('should get state', async () => {
|
||||
state = await veilidClient.getState();
|
||||
expect(state.attachment).toBeDefined();
|
||||
expect(state.config.config).toBeDefined();
|
||||
expect(state.network).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call debug command', async () => {
|
||||
const response = await veilidClient.debug('txtrecord');
|
||||
expect(response).toBeDefined();
|
||||
expect(response.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
38
veilid-wasm/tests/src/veilidCrypto.test.ts
Normal file
38
veilid-wasm/tests/src/veilidCrypto.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { expect } from '@wdio/globals';
|
||||
|
||||
import {
|
||||
veilidCoreInitConfig,
|
||||
veilidCoreStartupConfig,
|
||||
} from './utils/veilid-config';
|
||||
|
||||
import { veilidClient, veilidCrypto } from 'veilid-wasm';
|
||||
|
||||
describe('veilidCrypto', () => {
|
||||
before('veilid startup', async () => {
|
||||
veilidClient.initializeCore(veilidCoreInitConfig);
|
||||
await veilidClient.startupCore((_update) => {
|
||||
// if (_update.kind === 'Log') {
|
||||
// console.log(_update.message);
|
||||
// }
|
||||
}, JSON.stringify(veilidCoreStartupConfig));
|
||||
});
|
||||
|
||||
after('veilid shutdown', async () => {
|
||||
await veilidClient.shutdownCore();
|
||||
});
|
||||
|
||||
it('should list crypto kinds', () => {
|
||||
const kinds = veilidCrypto.validCryptoKinds();
|
||||
const bestKind = veilidCrypto.bestCryptoKind();
|
||||
|
||||
expect(typeof bestKind).toBe('string');
|
||||
expect(kinds.includes(bestKind)).toBe(true);
|
||||
});
|
||||
|
||||
it('should generate key pair', async () => {
|
||||
const bestKind = veilidCrypto.bestCryptoKind();
|
||||
const keypair = veilidCrypto.generateKeyPair(bestKind);
|
||||
expect(typeof keypair).toBe('string');
|
||||
// TODO: fix TypeScript return type of generateKeyPair to return string instead of KeyPair
|
||||
});
|
||||
});
|
24
veilid-wasm/tests/tsconfig.json
Normal file
24
veilid-wasm/tests/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"module": "ESNext",
|
||||
"target": "es2022",
|
||||
"types": [
|
||||
"node",
|
||||
"@wdio/globals/types",
|
||||
"expect-webdriverio",
|
||||
"@wdio/mocha-framework",
|
||||
"@wdio/browser-runner"
|
||||
],
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
5
veilid-wasm/tests/vite.config.ts
Normal file
5
veilid-wasm/tests/vite.config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import wasm from 'vite-plugin-wasm';
|
||||
export default defineConfig({
|
||||
plugins: [wasm()],
|
||||
});
|
300
veilid-wasm/tests/wdio.conf.ts
Normal file
300
veilid-wasm/tests/wdio.conf.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
import type { Options } from '@wdio/types';
|
||||
export const config: Options.Testrunner = {
|
||||
//
|
||||
// ====================
|
||||
// Runner Configuration
|
||||
// ====================
|
||||
// WebdriverIO supports running e2e tests as well as unit and component tests.
|
||||
runner: ['browser', { viteConfig: './vite.config.ts' }],
|
||||
autoCompileOpts: {
|
||||
autoCompile: true,
|
||||
tsNodeOpts: {
|
||||
project: './tsconfig.json',
|
||||
typeCheck: true,
|
||||
},
|
||||
},
|
||||
|
||||
//
|
||||
// ==================
|
||||
// Specify Test Files
|
||||
// ==================
|
||||
// Define which test specs should run. The pattern is relative to the directory
|
||||
// of the configuration file being run.
|
||||
//
|
||||
// The specs are defined as an array of spec files (optionally using wildcards
|
||||
// that will be expanded). The test for each spec file will be run in a separate
|
||||
// worker process. In order to have a group of spec files run in the same worker
|
||||
// process simply enclose them in an array within the specs array.
|
||||
//
|
||||
// If you are calling `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script),
|
||||
// then the current working directory is where your `package.json` resides, so `wdio`
|
||||
// will be called from there.
|
||||
//
|
||||
specs: ['./src/**/*.test.ts'],
|
||||
// Patterns to exclude.
|
||||
exclude: [
|
||||
// 'path/to/excluded/files'
|
||||
],
|
||||
//
|
||||
// ============
|
||||
// Capabilities
|
||||
// ============
|
||||
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
|
||||
// time. Depending on the number of capabilities, WebdriverIO launches several test
|
||||
// sessions. Within your capabilities you can overwrite the spec and exclude options in
|
||||
// order to group specific specs to a specific capability.
|
||||
//
|
||||
// First, you can define how many instances should be started at the same time. Let's
|
||||
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
|
||||
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
|
||||
// files and you set maxInstances to 10, all spec files will get tested at the same time
|
||||
// and 30 processes will get spawned. The property handles how many capabilities
|
||||
// from the same test should run tests.
|
||||
//
|
||||
maxInstances: process.env.WDIO_HEADLESS ? 10 : 1,
|
||||
//
|
||||
// If you have trouble getting all important capabilities together, check out the
|
||||
// Sauce Labs platform configurator - a great tool to configure your capabilities:
|
||||
// https://saucelabs.com/platform/platform-configurator
|
||||
//
|
||||
capabilities: [
|
||||
{
|
||||
// capabilities for local browser web tests
|
||||
browserName: 'firefox', // or "chrome", "microsoftedge", "safari"
|
||||
'moz:firefoxOptions': {
|
||||
args: process.env.WDIO_HEADLESS ? ['-headless'] : [],
|
||||
},
|
||||
},
|
||||
// {
|
||||
// browserName: 'chrome',
|
||||
// 'goog:chromeOptions': {
|
||||
// args: process.env.WDIO_HEADLESS ? ['headless', 'disable-gpu'] : [],
|
||||
// },
|
||||
// },
|
||||
],
|
||||
|
||||
//
|
||||
// ===================
|
||||
// Test Configurations
|
||||
// ===================
|
||||
// Define all options that are relevant for the WebdriverIO instance here
|
||||
//
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
logLevel: 'warn',
|
||||
//
|
||||
// Set specific log levels per logger
|
||||
// loggers:
|
||||
// - webdriver, webdriverio
|
||||
// - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
|
||||
// - @wdio/mocha-framework, @wdio/jasmine-framework
|
||||
// - @wdio/local-runner
|
||||
// - @wdio/sumologic-reporter
|
||||
// - @wdio/cli, @wdio/config, @wdio/utils
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
// logLevels: {
|
||||
// webdriver: 'info',
|
||||
// '@wdio/appium-service': 'info'
|
||||
// },
|
||||
//
|
||||
// If you only want to run your tests until a specific amount of tests have failed use
|
||||
// bail (default is 0 - don't bail, run all tests).
|
||||
bail: 0,
|
||||
//
|
||||
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
|
||||
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
|
||||
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
|
||||
// gets prepended directly.
|
||||
baseUrl: '',
|
||||
//
|
||||
// Default timeout for all waitFor* commands.
|
||||
waitforTimeout: 10000,
|
||||
//
|
||||
// Default timeout in milliseconds for request
|
||||
// if browser driver or grid doesn't send response
|
||||
connectionRetryTimeout: 120000,
|
||||
//
|
||||
// Default request retries count
|
||||
connectionRetryCount: 3,
|
||||
//
|
||||
// Test runner services
|
||||
// Services take over a specific job you don't want to take care of. They enhance
|
||||
// your test setup with almost no effort. Unlike plugins, they don't add new
|
||||
// commands. Instead, they hook themselves up into the test process.
|
||||
// services: [],
|
||||
//
|
||||
// Framework you want to run your specs with.
|
||||
// The following are supported: Mocha, Jasmine, and Cucumber
|
||||
// see also: https://webdriver.io/docs/frameworks
|
||||
//
|
||||
// Make sure you have the wdio adapter package for the specific framework installed
|
||||
// before running any tests.
|
||||
framework: 'mocha',
|
||||
//
|
||||
// The number of times to retry the entire specfile when it fails as a whole
|
||||
// specFileRetries: 1,
|
||||
//
|
||||
// Delay in seconds between the spec file retry attempts
|
||||
// specFileRetriesDelay: 0,
|
||||
//
|
||||
// Whether or not retried spec files should be retried immediately or deferred to the end of the queue
|
||||
// specFileRetriesDeferred: false,
|
||||
//
|
||||
// Test reporter for stdout.
|
||||
// The only one supported by default is 'dot'
|
||||
// see also: https://webdriver.io/docs/dot-reporter
|
||||
reporters: ['spec'],
|
||||
|
||||
//
|
||||
// Options to be passed to Mocha.
|
||||
// See the full list at http://mochajs.org/
|
||||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
timeout: 60000,
|
||||
},
|
||||
//
|
||||
// =====
|
||||
// Hooks
|
||||
// =====
|
||||
// WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
|
||||
// it and to build services around it. You can either apply a single function or an array of
|
||||
// methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
|
||||
// resolved to continue.
|
||||
/**
|
||||
* Gets executed once before all workers get launched.
|
||||
* @param {object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
*/
|
||||
// onPrepare: function (config, capabilities) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed before a worker process is spawned and can be used to initialise specific service
|
||||
* for that worker as well as modify runtime environments in an async fashion.
|
||||
* @param {string} cid capability id (e.g 0-0)
|
||||
* @param {object} caps object containing capabilities for session that will be spawn in the worker
|
||||
* @param {object} specs specs to be run in the worker process
|
||||
* @param {object} args object that will be merged with the main configuration once worker is initialized
|
||||
* @param {object} execArgv list of string arguments passed to the worker process
|
||||
*/
|
||||
// onWorkerStart: function (cid, caps, specs, args, execArgv) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed just after a worker process has exited.
|
||||
* @param {string} cid capability id (e.g 0-0)
|
||||
* @param {number} exitCode 0 - success, 1 - fail
|
||||
* @param {object} specs specs to be run in the worker process
|
||||
* @param {number} retries number of retries used
|
||||
*/
|
||||
// onWorkerEnd: function (cid, exitCode, specs, retries) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed just before initialising the webdriver session and test framework. It allows you
|
||||
* to manipulate configurations depending on the capability or spec.
|
||||
* @param {object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that are to be run
|
||||
* @param {string} cid worker id (e.g. 0-0)
|
||||
*/
|
||||
// beforeSession: function (config, capabilities, specs, cid) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed before test execution begins. At this point you can access to all global
|
||||
* variables like `browser`. It is the perfect place to define custom commands.
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that are to be run
|
||||
* @param {object} browser instance of created browser/device session
|
||||
*/
|
||||
// before: function (capabilities, specs) {
|
||||
// },
|
||||
/**
|
||||
* Runs before a WebdriverIO command gets executed.
|
||||
* @param {string} commandName hook command name
|
||||
* @param {Array} args arguments that command would receive
|
||||
*/
|
||||
// beforeCommand: function (commandName, args) {
|
||||
// },
|
||||
/**
|
||||
* Hook that gets executed before the suite starts
|
||||
* @param {object} suite suite details
|
||||
*/
|
||||
// beforeSuite: function (suite) {
|
||||
// },
|
||||
/**
|
||||
* Function to be executed before a test (in Mocha/Jasmine) starts.
|
||||
*/
|
||||
// beforeTest: function (test, context) {
|
||||
// },
|
||||
/**
|
||||
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
|
||||
* beforeEach in Mocha)
|
||||
*/
|
||||
// beforeHook: function (test, context) {
|
||||
// },
|
||||
/**
|
||||
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
|
||||
* afterEach in Mocha)
|
||||
*/
|
||||
// afterHook: function (test, context, { error, result, duration, passed, retries }) {
|
||||
// },
|
||||
/**
|
||||
* Function to be executed after a test (in Mocha/Jasmine only)
|
||||
* @param {object} test test object
|
||||
* @param {object} context scope object the test was executed with
|
||||
* @param {Error} result.error error object in case the test fails, otherwise `undefined`
|
||||
* @param {*} result.result return object of test function
|
||||
* @param {number} result.duration duration of test
|
||||
* @param {boolean} result.passed true if test has passed, otherwise false
|
||||
* @param {object} result.retries information about spec related retries, e.g. `{ attempts: 0, limit: 0 }`
|
||||
*/
|
||||
// afterTest: function(test, context, { error, result, duration, passed, retries }) {
|
||||
// },
|
||||
|
||||
/**
|
||||
* Hook that gets executed after the suite has ended
|
||||
* @param {object} suite suite details
|
||||
*/
|
||||
// afterSuite: function (suite) {
|
||||
// },
|
||||
/**
|
||||
* Runs after a WebdriverIO command gets executed
|
||||
* @param {string} commandName hook command name
|
||||
* @param {Array} args arguments that command would receive
|
||||
* @param {number} result 0 - command success, 1 - command error
|
||||
* @param {object} error error object if any
|
||||
*/
|
||||
// afterCommand: function (commandName, args, result, error) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed after all tests are done. You still have access to all global variables from
|
||||
* the test.
|
||||
* @param {number} result 0 - test pass, 1 - test fail
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that ran
|
||||
*/
|
||||
// after: function (result, capabilities, specs) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed right after terminating the webdriver session.
|
||||
* @param {object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that ran
|
||||
*/
|
||||
// afterSession: function (config, capabilities, specs) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed after all workers got shut down and the process is about to exit. An error
|
||||
* thrown in the onComplete hook will result in the test run failing.
|
||||
* @param {object} exitCode 0 - success, 1 - fail
|
||||
* @param {object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {<Object>} results object containing test results
|
||||
*/
|
||||
// onComplete: function(exitCode, config, capabilities, results) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed when a refresh happens.
|
||||
* @param {string} oldSessionId session ID of the old session
|
||||
* @param {string} newSessionId session ID of the new session
|
||||
*/
|
||||
// onReload: function(oldSessionId, newSessionId) {
|
||||
// }
|
||||
};
|
@@ -1,218 +0,0 @@
|
||||
//! Test suite for the Web and headless browsers.
|
||||
//! These tests only work with WASM_BINDGEN_USE_NO_MODULE=true env var,
|
||||
//! as otherwise there's no way to access the generated wasm bindings from inside JS.
|
||||
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate wasm_bindgen_test;
|
||||
use js_sys::*;
|
||||
use parking_lot::Once;
|
||||
use veilid_wasm::*;
|
||||
use wasm_bindgen::*;
|
||||
use wasm_bindgen_futures::*;
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
static SETUP_ONCE: Once = Once::new();
|
||||
pub fn setup() -> () {
|
||||
SETUP_ONCE.call_once(|| {
|
||||
console_log!("setup()");
|
||||
console_error_panic_hook::set_once();
|
||||
init_callbacks();
|
||||
})
|
||||
}
|
||||
|
||||
fn init_callbacks() {
|
||||
assert_eq!(js_sys::eval(r#"
|
||||
window.sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) };
|
||||
window.stateChangeCallback = async (stateChange) => {
|
||||
delete stateChange.peers; // makes logs less verbose
|
||||
console.log("State change: ", JSON.stringify(stateChange, null, 2));
|
||||
};
|
||||
window.veilidCoreInitConfig = {
|
||||
logging: {
|
||||
api: {
|
||||
enabled: true,
|
||||
level: 'Info',
|
||||
},
|
||||
performance: {
|
||||
enabled: false,
|
||||
level: 'Info',
|
||||
logs_in_timings: false,
|
||||
logs_in_console: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
window.veilidCoreStartupConfig = {
|
||||
program_name: 'veilid-wasm-test',
|
||||
namespace: '',
|
||||
capabilities: {
|
||||
disable: [],
|
||||
},
|
||||
protected_store: {
|
||||
allow_insecure_fallback: true,
|
||||
always_use_insecure_storage: true,
|
||||
directory: '',
|
||||
delete: false,
|
||||
device_encryption_key_password: 'some-user-secret-value',
|
||||
// "new_device_encryption_key_password": "an-updated-user-secret-value"
|
||||
},
|
||||
table_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
block_store: {
|
||||
directory: '',
|
||||
delete: false,
|
||||
},
|
||||
network: {
|
||||
connection_initial_timeout_ms: 2000,
|
||||
connection_inactivity_timeout_ms: 60000,
|
||||
max_connections_per_ip4: 32,
|
||||
max_connections_per_ip6_prefix: 32,
|
||||
max_connections_per_ip6_prefix_size: 56,
|
||||
max_connection_frequency_per_min: 128,
|
||||
client_whitelist_timeout_ms: 300000,
|
||||
reverse_connection_receipt_time_ms: 5000,
|
||||
hole_punch_receipt_time_ms: 5000,
|
||||
network_key_password: '',
|
||||
disable_capabilites: [],
|
||||
routing_table: {
|
||||
node_id: [],
|
||||
node_id_secret: [],
|
||||
bootstrap: [
|
||||
'ws://bootstrap.veilid.net:5150/ws',
|
||||
],
|
||||
limit_over_attached: 64,
|
||||
limit_fully_attached: 32,
|
||||
limit_attached_strong: 16,
|
||||
limit_attached_good: 8,
|
||||
limit_attached_weak: 4,
|
||||
},
|
||||
rpc: {
|
||||
concurrency: 0,
|
||||
queue_size: 1024,
|
||||
max_timestamp_behind_ms: 10000,
|
||||
max_timestamp_ahead_ms: 10000,
|
||||
timeout_ms: 5000,
|
||||
max_route_hop_count: 4,
|
||||
default_route_hop_count: 1,
|
||||
},
|
||||
dht: {
|
||||
max_find_node_count: 20,
|
||||
resolve_node_timeout_ms: 10000,
|
||||
resolve_node_count: 1,
|
||||
resolve_node_fanout: 4,
|
||||
get_value_timeout_ms: 10000,
|
||||
get_value_count: 3,
|
||||
get_value_fanout: 4,
|
||||
set_value_timeout_ms: 10000,
|
||||
set_value_count: 5,
|
||||
set_value_fanout: 4,
|
||||
min_peer_count: 20,
|
||||
min_peer_refresh_time_ms: 60000,
|
||||
validate_dial_info_receipt_time_ms: 2000,
|
||||
local_subkey_cache_size: 128,
|
||||
local_max_subkey_cache_memory_mb: 256,
|
||||
remote_subkey_cache_size: 1024,
|
||||
remote_max_records: 65536,
|
||||
remote_max_subkey_cache_memory_mb: 256,
|
||||
remote_max_storage_space_mb: 0,
|
||||
},
|
||||
upnp: true,
|
||||
detect_address_changes: true,
|
||||
restricted_nat_retries: 0,
|
||||
tls: {
|
||||
certificate_path: '',
|
||||
private_key_path: '',
|
||||
connection_initial_timeout_ms: 2000,
|
||||
},
|
||||
application: {
|
||||
https: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
http: {
|
||||
enabled: false,
|
||||
listen_address: ':5150',
|
||||
path: 'app',
|
||||
},
|
||||
},
|
||||
protocol: {
|
||||
udp: {
|
||||
enabled: false,
|
||||
socket_pool_size: 0,
|
||||
listen_address: '',
|
||||
},
|
||||
tcp: {
|
||||
connect: false,
|
||||
listen: false,
|
||||
max_connections: 32,
|
||||
listen_address: '',
|
||||
},
|
||||
ws: {
|
||||
connect: true,
|
||||
listen: true,
|
||||
max_connections: 16,
|
||||
listen_address: ':5150',
|
||||
path: 'ws',
|
||||
},
|
||||
wss: {
|
||||
connect: true,
|
||||
listen: false,
|
||||
max_connections: 16,
|
||||
listen_address: '',
|
||||
path: 'ws',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
true
|
||||
"#).expect("failed to eval"), JsValue::TRUE);
|
||||
}
|
||||
|
||||
/// Helper for converting an eval Promise result into a JsValue
|
||||
async fn eval_promise(source: &str) -> JsValue {
|
||||
JsFuture::from(
|
||||
eval(source)
|
||||
.expect("Failed to eval")
|
||||
.dyn_into::<Promise>()
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// TODO: now that veilidClient uses a single instance of VeilidAPI,
|
||||
// subsequent tests fail because veilidCore has already been initialized.
|
||||
#[wasm_bindgen_test()]
|
||||
async fn test_kitchen_sink() {
|
||||
setup();
|
||||
|
||||
let res = eval_promise(
|
||||
r#"
|
||||
(async function () {
|
||||
const { veilidClient } = wasm_bindgen; // only accessible in no_module mode.
|
||||
veilidClient.initializeCore(window.veilidCoreInitConfig);
|
||||
await veilidClient.startupCore(window.stateChangeCallback, JSON.stringify(window.veilidCoreStartupConfig));
|
||||
|
||||
console.log(veilidClient.versionString());
|
||||
await veilidClient.attach();
|
||||
|
||||
await sleep(10000);
|
||||
await veilidClient.detach();
|
||||
await veilidClient.shutdownCore();
|
||||
|
||||
return true;
|
||||
})();
|
||||
"#,
|
||||
).await;
|
||||
|
||||
assert_eq!(res, JsValue::TRUE);
|
||||
}
|
Reference in New Issue
Block a user