فهرست منبع

test(e2e): run datachannel serialization tests

Jonas Gloning 1 سال پیش
والد
کامیت
d9d9407d35

+ 39 - 0
.github/workflows/browserstack.yml

@@ -0,0 +1,39 @@
+name: "BrowserStack Test"
+on: [push, pull_request]
+jobs:
+  ubuntu-job:
+    name: "BrowserStack Test on Ubuntu"
+    runs-on: ubuntu-latest # Can be self-hosted runner also
+    steps:
+      - name: "BrowserStack Env Setup" # Invokes the setup-env action
+        uses: browserstack/github-actions/setup-env@master
+        with:
+          username: ${{ secrets.BROWSERSTACK_USERNAME }}
+          access-key: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
+
+      - name: "BrowserStack Local Tunnel Setup" # Invokes the setup-local action
+        uses: browserstack/github-actions/setup-local@master
+        with:
+          local-testing: start
+          local-identifier: peerjs-${{ github.run_id }}-${{ github.run_attempt }}
+
+      # The next 3 steps are for building the web application to be tested and starting the web server on the runner environment
+
+      - name: "Checkout the repository"
+        uses: actions/checkout@v2
+
+      - name: "Building web application to be tested"
+        run: npm install && npm run build
+
+      - name: "Running application under test"
+        run: npx http-server -p 3000 --cors &
+
+      - name: "Running test on BrowserStack" # Invokes the actual test script that would run on BrowserStack browsers
+        run: npm run e2e:bstack # See sample test script above
+        env:
+          BROWSERSTACK_LOCAL_IDENTIFIER: peerjs-${{ github.run_id }}-${{ github.run_attempt }}
+
+      - name: "BrowserStackLocal Stop" # Terminating the BrowserStackLocal tunnel connection
+        uses: browserstack/github-actions/setup-local@master
+        with:
+          local-testing: stop

+ 1 - 0
browserstack.err

@@ -0,0 +1 @@
+[object Object]

+ 5 - 0
e2e/.eslintrc

@@ -0,0 +1,5 @@
+{
+	"env": {
+		"browser": true
+	}
+}

+ 5 - 0
e2e/alice.html

@@ -0,0 +1,5 @@
+<html>
+	<head>
+		<title>Alice</title>
+	</head>
+</html>

+ 5 - 0
e2e/bob.html

@@ -0,0 +1,5 @@
+<html>
+	<head>
+		<title>Bob</title>
+	</head>
+</html>

+ 1385 - 0
e2e/commit_data.js

@@ -0,0 +1,1385 @@
+export const commit_data = [
+	{
+		created_at: "2013-11-07T19:41:25-08:00",
+		payload: { issue_id: 22111847, comment_id: 28032260 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/101#issuecomment-28032260",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-07T19:35:50-08:00",
+		payload: { issue_id: 22196839, comment_id: 28031970 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/103#issuecomment-28031970",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-02T15:18:51-07:00",
+		payload: {
+			ref: "0.3.3",
+			ref_type: "tag",
+			master_branch: "master",
+			description: "Peer-to-peer data in the browser.",
+		},
+		public: true,
+		type: "CreateEvent",
+		url: "https://github.com/peers/peerjs/tree/0.3.3",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-02T15:18:49-07:00",
+		payload: {
+			shas: [
+				[
+					"9976990c61c0f9c3c44f1de2a997ff8f21013d2a",
+					"really.ez@gmail.com",
+					"Bump to 0.3.3",
+					"ericz",
+					true,
+				],
+			],
+			size: 1,
+			ref: "refs/heads/master",
+			head: "9976990c61c0f9c3c44f1de2a997ff8f21013d2a",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/c9adf5076e...9976990c61",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-02T15:15:18-07:00",
+		payload: {
+			shas: [
+				[
+					"ec1424c0f264ea5d8ce08ac2cc9ea2bd027a6a71",
+					"really.ez@gmail.com",
+					"Errant comma",
+					"ericz",
+					true,
+				],
+				[
+					"c9adf5076ea41df60231e11d032f371939228609",
+					"really.ez@gmail.com",
+					"Dont throw exception on failures",
+					"ericz",
+					true,
+				],
+			],
+			size: 2,
+			ref: "refs/heads/master",
+			head: "c9adf5076ea41df60231e11d032f371939228609",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/bb1045bf92...c9adf5076e",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-02T15:02:02-07:00",
+		payload: {
+			shas: [
+				[
+					"bb1045bf92fbaef6e2156c3ac47015f70af5d866",
+					"really.ez@gmail.com",
+					"Fix errant comma",
+					"ericz",
+					true,
+				],
+			],
+			size: 1,
+			ref: "refs/heads/master",
+			head: "bb1045bf92fbaef6e2156c3ac47015f70af5d866",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/2db1c59998...bb1045bf92",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-02T14:56:14-07:00",
+		payload: {
+			shas: [
+				[
+					"2db1c599987753079d197f73272a9e40e9290f73",
+					"really.ez@gmail.com",
+					"Remove errant comma",
+					"ericz",
+					true,
+				],
+			],
+			size: 1,
+			ref: "refs/heads/master",
+			head: "2db1c599987753079d197f73272a9e40e9290f73",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/214a14cc10...2db1c59998",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-02T14:56:13-07:00",
+		payload: {
+			shas: [
+				[
+					"841921c349aff234b022bb966774d00ae22fef5e",
+					"really.ez@gmail.com",
+					"Errant comma",
+					"ericz",
+					true,
+				],
+			],
+			size: 1,
+			ref: "refs/heads/better-supports",
+			head: "841921c349aff234b022bb966774d00ae22fef5e",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/ccd80612ae...841921c349",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-11-01T11:41:34-07:00",
+		payload: {
+			shas: [
+				[
+					"37350aaef3763d5a1bc63c4903f0f34ea9780d36",
+					"really.ez@gmail.com",
+					"Fix",
+					"Eric Zhang",
+					true,
+				],
+			],
+			size: 1,
+			ref: "refs/heads/master",
+			head: "37350aaef3763d5a1bc63c4903f0f34ea9780d36",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/HackBerkeley/ascam/compare/7d76223acc...37350aaef3",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 5557070,
+			name: "ascam",
+			url: "https://github.com/HackBerkeley/ascam",
+			description: "Ascii Webcam",
+			homepage: "",
+			watchers: 1,
+			stargazers: 1,
+			forks: 1,
+			fork: true,
+			size: 1973,
+			owner: "HackBerkeley",
+			private: false,
+			open_issues: 0,
+			has_issues: false,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-08-25T20:19:01-07:00",
+			pushed_at: "2013-11-01T11:41:33-07:00",
+			master_branch: "master",
+			organization: "HackBerkeley",
+		},
+	},
+	{
+		created_at: "2013-10-31T10:56:20-07:00",
+		payload: { issue_id: 13813188, comment_id: 27509702 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/pull/45#issuecomment-27509702",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-26T22:53:49-07:00",
+		payload: { issue_id: 21646195, comment_id: 27163465 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs-server/issues/25#issuecomment-27163465",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7452705,
+			name: "peerjs-server",
+			url: "https://github.com/peers/peerjs-server",
+			description: "Server for PeerJS",
+			homepage: "https://peerjs.com",
+			watchers: 328,
+			stargazers: 328,
+			forks: 56,
+			fork: false,
+			size: 389,
+			owner: "peers",
+			private: false,
+			open_issues: 12,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2013-01-04T22:49:08-08:00",
+			pushed_at: "2013-10-24T00:40:28-07:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T11:04:07-07:00",
+		payload: { action: "closed", issue: 16608955, number: 68 },
+		public: true,
+		type: "IssuesEvent",
+		url: "https://github.com/peers/peerjs/issues/68",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T11:02:50-07:00",
+		payload: { issue_id: 21379154, comment_id: 27113277 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/91#issuecomment-27113277",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T11:01:53-07:00",
+		payload: { action: "closed", issue: 21531959, number: 96 },
+		public: true,
+		type: "IssuesEvent",
+		url: "https://github.com/peers/peerjs/issues/96",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T11:01:25-07:00",
+		payload: { issue_id: 21379154, comment_id: 27113184 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/91#issuecomment-27113184",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T10:42:32-07:00",
+		payload: { issue_id: 21531959, comment_id: 27111740 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/96#issuecomment-27111740",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T10:42:13-07:00",
+		payload: { issue_id: 21531959, comment_id: 27111710 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/96#issuecomment-27111710",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-25T10:36:48-07:00",
+		payload: { issue_id: 21568882, comment_id: 27111312 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/97#issuecomment-27111312",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-23T15:52:46-07:00",
+		payload: { issue_id: 21487688, comment_id: 26953214 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/95#issuecomment-26953214",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-22T20:07:24-07:00",
+		payload: { action: "opened", issue: 21431237, number: 93 },
+		public: true,
+		type: "IssuesEvent",
+		url: "https://github.com/peers/peerjs/issues/93",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-22T19:15:46-07:00",
+		payload: { issue_id: 21259595, comment_id: 26875922 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/89#issuecomment-26875922",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-22T19:06:59-07:00",
+		payload: { issue_id: 20917093, comment_id: 26875655 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/86#issuecomment-26875655",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-22T10:42:17-07:00",
+		payload: { issue_id: 21337614, comment_id: 26824752 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/90#issuecomment-26824752",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-21T21:00:18-07:00",
+		payload: { issue_id: 21337614, comment_id: 26775684 },
+		public: true,
+		type: "IssueCommentEvent",
+		url: "https://github.com/peers/peerjs/issues/90#issuecomment-26775684",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-19T02:06:52-07:00",
+		payload: {
+			ref: "0.3.1",
+			ref_type: "tag",
+			master_branch: "master",
+			description: "Peer-to-peer data in the browser.",
+		},
+		public: true,
+		type: "CreateEvent",
+		url: "https://github.com/peers/peerjs/tree/0.3.1",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-19T02:06:43-07:00",
+		payload: { ref: "0.3.1", ref_type: "tag" },
+		public: true,
+		type: "DeleteEvent",
+		url: "https://github.com/",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-19T02:05:42-07:00",
+		payload: {
+			shas: [
+				[
+					"720eb3e881220f78eaca3d715ce7afe9324d1a3e",
+					"really.ez@gmail.com",
+					"0.3.1",
+					"ericz",
+					true,
+				],
+				[
+					"79e10688c56524479f3b2c0cb069c4ac7e065b57",
+					"really.ez@gmail.com",
+					"Set maxRetransmits to 0 when reliable false",
+					"ericz",
+					true,
+				],
+			],
+			size: 2,
+			ref: "refs/heads/master",
+			head: "79e10688c56524479f3b2c0cb069c4ac7e065b57",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/b474a4cba6...79e10688c5",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-19T02:02:15-07:00",
+		payload: {
+			ref: "0.3.1",
+			ref_type: "tag",
+			master_branch: "master",
+			description: "Peer-to-peer data in the browser.",
+		},
+		public: true,
+		type: "CreateEvent",
+		url: "https://github.com/peers/peerjs/tree/0.3.1",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-19T02:02:13-07:00",
+		payload: {
+			shas: [
+				[
+					"b474a4cba6156dabd1312cd25a520b4286e362f6",
+					"really.ez@gmail.com",
+					"Setting reliable to false by default",
+					"ericz",
+					true,
+				],
+			],
+			size: 1,
+			ref: "refs/heads/master",
+			head: "b474a4cba6156dabd1312cd25a520b4286e362f6",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/93fc4931b2...b474a4cba6",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+	{
+		created_at: "2013-10-19T01:53:16-07:00",
+		payload: {
+			shas: [
+				[
+					"3949c236345171987b9291059fbaf9024eeca680",
+					"really.ez@gmail.com",
+					"0.3.1",
+					"ericz",
+					true,
+				],
+				[
+					"93fc4931b24c0261c5fda71e0441a5ee8bda70b2",
+					"really.ez@gmail.com",
+					"Update reliable doc",
+					"ericz",
+					true,
+				],
+			],
+			size: 2,
+			ref: "refs/heads/master",
+			head: "93fc4931b24c0261c5fda71e0441a5ee8bda70b2",
+		},
+		public: true,
+		type: "PushEvent",
+		url: "https://github.com/peers/peerjs/compare/cd287e2fae...93fc4931b2",
+		actor: "ericz",
+		actor_attributes: {
+			login: "ericz",
+			type: "User",
+			gravatar_id: "c584ef7fe434331f7068ea49cacd88b9",
+			name: "Eric Zhang",
+			company: "Lever",
+			blog: "https://twitter.com/reallyez",
+			location: "Berkeley",
+			email: "eric@ericzhang.com",
+		},
+		repository: {
+			id: 7292898,
+			name: "peerjs",
+			url: "https://github.com/peers/peerjs",
+			description: "Peer-to-peer data in the browser.",
+			homepage: "https://peerjs.com",
+			watchers: 1647,
+			stargazers: 1647,
+			forks: 145,
+			fork: false,
+			size: 2188,
+			owner: "peers",
+			private: false,
+			open_issues: 20,
+			has_issues: true,
+			has_downloads: true,
+			has_wiki: true,
+			language: "JavaScript",
+			created_at: "2012-12-22T23:28:47-08:00",
+			pushed_at: "2013-11-09T22:58:31-08:00",
+			master_branch: "master",
+			organization: "peers",
+		},
+	},
+];

+ 72 - 0
e2e/data.js

@@ -0,0 +1,72 @@
+export const numbers = [
+	0,
+	1,
+	-1,
+	//
+	Math.PI,
+	-Math.PI,
+	//8 bit
+	0x7f,
+	0x0f,
+	//16 bit
+	0x7fff,
+	0x0fff,
+	//32 bit
+	0x7fffffff,
+	0x0fffffff,
+	//64 bit
+	// 0x7FFFFFFFFFFFFFFF,
+	// eslint-disable-next-line no-loss-of-precision
+	0x0fffffffffffffff,
+];
+export const long_string = "ThisIsÁTèstString".repeat(100000);
+export const strings = [
+	"",
+	"hello",
+	"café",
+	"中文",
+	"broccoli🥦līp𨋢grin😃ok",
+	"\u{10ffff}",
+];
+
+export { commit_data } from "./commit_data.js";
+
+export const typed_arrays = [
+	new Uint8Array(),
+	new Uint8Array([0]),
+	new Uint8Array([0, 1, 2, 3, 4, 6, 7]),
+	new Uint8Array([0, 1, 2, 3, 4, 6, 78, 9, 10, 11, 12, 13, 14, 15]),
+	new Uint8Array([
+		0, 1, 2, 3, 4, 6, 78, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 30, 31,
+	]),
+	new Int32Array([0].map((x) => -x)),
+	new Int32Array([0, 1, 2, 3, 4, 6, 7].map((x) => -x)),
+	new Int32Array(
+		[0, 1, 2, 3, 4, 6, 78, 9, 10, 11, 12, 13, 14, 15].map((x) => -x),
+	),
+	new Int32Array(
+		[
+			0, 1, 2, 3, 4, 6, 78, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22,
+			23, 24, 25, 26, 27, 28, 30, 31,
+		].map((x) => -x),
+	),
+];
+
+export const typed_array_view = new Uint8Array(typed_arrays[6].buffer, 4);
+
+export const array_buffers = [
+	new Uint8Array(),
+	new Uint8Array([0]),
+	new Uint8Array([0, 1, 2, 3, 4, 6, 7]),
+	new Uint8Array([0, 1, 2, 3, 4, 6, 78, 9, 10, 11, 12, 13, 14, 15]),
+	new Uint8Array([
+		0, 1, 2, 3, 4, 6, 78, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23,
+		24, 25, 26, 27, 28, 30, 31,
+	]),
+].map((x) => x.buffer);
+
+export const dates = [
+	new Date(Date.UTC(2024, 1, 1, 1, 1, 1, 1)),
+	new Date(Date.UTC(1, 1, 1, 1, 1, 1, 1)),
+];

+ 37 - 0
e2e/datachannel/arraybuffers.js

@@ -0,0 +1,37 @@
+import { typed_arrays, typed_array_view, array_buffers } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	for (const [i, typed_array] of typed_arrays.entries()) {
+		expect(received[i]).to.be.an.instanceof(ArrayBuffer);
+		expect(received[i]).to.deep.equal(typed_array.buffer);
+	}
+	for (const [i, array_buffer] of array_buffers.entries()) {
+		expect(received[typed_arrays.length + i]).to.be.an.instanceof(ArrayBuffer);
+		expect(received[typed_arrays.length + i]).to.deep.equal(array_buffer);
+	}
+
+	const received_typed_array_view =
+		received[typed_arrays.length + array_buffers.length];
+	expect(new Uint8Array(received_typed_array_view)).to.deep.equal(
+		typed_array_view,
+	);
+	for (const [i, v] of new Uint8Array(received_typed_array_view).entries()) {
+		expect(v).to.deep.equal(typed_array_view[i]);
+	}
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	for (const typed_array of typed_arrays) {
+		dataConnection.send(typed_array);
+	}
+	for (const array_buffer of array_buffers) {
+		dataConnection.send(array_buffer);
+	}
+	dataConnection.send(typed_array_view);
+};
+
+window["connect-btn"].disabled = false;

+ 15 - 0
e2e/datachannel/arrays.js

@@ -0,0 +1,15 @@
+import { commit_data } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	expect(received).to.deep.equal([[], commit_data]);
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	dataConnection.send([]);
+	dataConnection.send(commit_data);
+};
+window["connect-btn"].disabled = false;

+ 19 - 0
e2e/datachannel/arrays_json.js

@@ -0,0 +1,19 @@
+/**
+ * JSON transfer does not chunk, commit_data is too large to send
+ */
+
+import { commit_data } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	expect(received).to.deep.equal([[], commit_data.slice(0, 2)]);
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	dataConnection.send([]);
+	dataConnection.send(commit_data.slice(0, 2));
+};
+window["connect-btn"].disabled = false;

+ 16 - 0
e2e/datachannel/numbers.js

@@ -0,0 +1,16 @@
+import { numbers } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	expect(received).to.deep.equal(numbers);
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	for (const number of numbers) {
+		dataConnection.send(number);
+	}
+};
+window["connect-btn"].disabled = false;

+ 16 - 0
e2e/datachannel/objects.js

@@ -0,0 +1,16 @@
+import { commit_data } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	expect(received).to.deep.equal(commit_data);
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	for (const commit of commit_data) {
+		dataConnection.send(commit);
+	}
+};
+window["connect-btn"].disabled = false;

+ 27 - 0
e2e/datachannel/serialization.html

@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="UTF-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title></title>
+		<link rel="stylesheet" href="../style.css" />
+	</head>
+	<body>
+		<h1>Serialization</h1>
+		<div id="inputs">
+			<input type="text" id="receiver-id" placeholder="Receiver ID" />
+			<button id="connect-btn" disabled>Connect</button>
+			<button id="send-btn">Send</button>
+			<button id="check-btn">Check</button>
+		</div>
+		<div id="messages"></div>
+		<div id="result"></div>
+		<div id="error-message"></div>
+		<script src="/dist/peerjs.js"></script>
+		<!--<script src="https://unpkg.com/peerjs@1.4.7/dist/peerjs.min.js"></script>-->
+		<script>
+			import(window.location.search.substring(6));
+		</script>
+		<script src="serialization.js" type="module"></script>
+	</body>
+</html>

+ 70 - 0
e2e/datachannel/serialization.js

@@ -0,0 +1,70 @@
+/**
+ * @type {typeof import("../peerjs").Peer}
+ */
+const Peer = window.Peer;
+
+document.getElementsByTagName("title")[0].innerText =
+	window.location.hash.substring(1);
+
+const checkBtn = document.getElementById("check-btn");
+const sendBtn = document.getElementById("send-btn");
+const receiverIdInput = document.getElementById("receiver-id");
+const connectBtn = document.getElementById("connect-btn");
+const messages = document.getElementById("messages");
+const result = document.getElementById("result");
+const errorMessage = document.getElementById("error-message");
+
+const peer = new Peer();
+const received = [];
+/**
+ * @type {import("../peerjs").DataConnection}
+ */
+let dataConnection;
+peer
+	.once("open", (id) => {
+		messages.textContent = `Your Peer ID: ${id}`;
+	})
+	.once("error", (error) => {
+		errorMessage.textContent = JSON.stringify(error);
+	})
+	.once("connection", (connection) => {
+		dataConnection = connection;
+		dataConnection.on("data", (data) => {
+			console.log(data);
+			received.push(data);
+		});
+		dataConnection.once("close", () => {
+			messages.textContent = "Closed!";
+		});
+	});
+
+connectBtn.addEventListener("click", () => {
+	const receiverId = receiverIdInput.value;
+	if (receiverId) {
+		dataConnection = peer.connect(receiverId);
+		dataConnection.once("open", () => {
+			messages.textContent = "Connected!";
+		});
+	}
+});
+
+checkBtn.addEventListener("click", async () => {
+	try {
+		window.check(received);
+		result.textContent = "Success!";
+	} catch (e) {
+		result.textContent = "Failed!";
+		errorMessage.textContent = JSON.stringify(e.message);
+	} finally {
+		messages.textContent = "Checked!";
+	}
+});
+
+sendBtn.addEventListener("click", () => {
+	dataConnection.once("error", (err) => {
+		errorMessage.innerText = err.toString();
+	});
+	window.send(dataConnection);
+	dataConnection.close({ flush: true });
+	messages.textContent = "Sent!";
+});

+ 71 - 0
e2e/datachannel/serialization.page.ts

@@ -0,0 +1,71 @@
+import { browser, $ } from "@wdio/globals";
+class SerializationPage {
+	get sendBtn() {
+		return $("button[id='send-btn']");
+	}
+
+	get checkBtn() {
+		return $("button[id='check-btn']");
+	}
+	get connectBtn() {
+		return $("button[id='connect-btn']");
+	}
+
+	get receiverId() {
+		return $("input[id='receiver-id']");
+	}
+
+	get messages() {
+		return $("div[id='messages']");
+	}
+
+	get errorMessage() {
+		return $("div[id='error-message']");
+	}
+
+	get result() {
+		return $("div[id='result']");
+	}
+
+	waitForMessage(right: string) {
+		return browser.waitUntil(
+			async () => {
+				const messages = await this.messages.getText();
+				return messages.startsWith(right);
+			},
+			{ timeoutMsg: `Expected message to start with ${right}`, timeout: 10000 },
+		);
+	}
+
+	async open(testFile: string, json: boolean = false) {
+		await browser.switchWindow("Alice");
+		await browser.url(
+			`/e2e/datachannel/serialization${
+				json ? "_json" : ""
+			}.html?test=${testFile}#Alice`,
+		);
+		await this.connectBtn.waitForEnabled();
+
+		await browser.switchWindow("Bob");
+		await browser.url(
+			`/e2e/datachannel/serialization${
+				json ? "_json" : ""
+			}.html?test=${testFile}#Bob`,
+		);
+		await this.connectBtn.waitForEnabled();
+	}
+	async init() {
+		await browser.url("/e2e/alice.html");
+		await browser.waitUntil(async () => {
+			const title = await browser.getTitle();
+			return title === "Alice";
+		});
+		await browser.newWindow("/e2e/bob.html");
+		await browser.waitUntil(async () => {
+			const title = await browser.getTitle();
+			return title === "Bob";
+		});
+	}
+}
+
+export default new SerializationPage();

+ 34 - 0
e2e/datachannel/serialization.spec.ts

@@ -0,0 +1,34 @@
+import P from "./serialization.page.js";
+import { browser, expect } from "@wdio/globals";
+
+const serializationTest = (testFile: string) => async () => {
+	await P.open(testFile);
+	await P.waitForMessage("Your Peer ID: ");
+	const bobId = (await P.messages.getText()).split("Your Peer ID: ")[1];
+	await browser.switchWindow("Alice");
+	await P.waitForMessage("Your Peer ID: ");
+	await P.receiverId.setValue(bobId);
+	await P.connectBtn.click();
+	await P.waitForMessage("Connected!");
+	await P.sendBtn.click();
+	await P.waitForMessage("Sent!");
+	await browser.switchWindow("Bob");
+	await P.waitForMessage("Closed!");
+	await P.checkBtn.click();
+	await P.waitForMessage("Checked!");
+
+	await expect(await P.errorMessage.getText()).toBe("");
+	await expect(await P.result.getText()).toBe("Success!");
+};
+describe("DataChannel:Default", () => {
+	beforeAll(async () => {
+		await P.init();
+	});
+	it("should transfer numbers", serializationTest("./numbers.js"));
+	/** ordering bug: chunked string not in order */
+	// it('should transfer strings', serializationTest("./strings.js"))
+	it("should transfer objects", serializationTest("./objects.js"));
+	it("should transfer arrays", serializationTest("./arrays.js"));
+	/** can't send bug */
+	// it('should transfer typed arrays / array buffers', serializationTest("./arraybuffers.js"))
+});

+ 26 - 0
e2e/datachannel/serialization_json.html

@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="UTF-8" />
+		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
+		<title></title>
+		<link rel="stylesheet" href="../style.css" />
+	</head>
+	<body>
+		<h1>Serialization</h1>
+		<div id="inputs">
+			<input type="text" id="receiver-id" placeholder="Receiver ID" />
+			<button id="connect-btn" disabled>Connect</button>
+			<button id="send-btn">Send</button>
+			<button id="check-btn">Check</button>
+		</div>
+		<div id="messages"></div>
+		<div id="result"></div>
+		<div id="error-message"></div>
+		<script src="/dist/peerjs.js"></script>
+		<script>
+			import(window.location.search.substring(6));
+		</script>
+		<script src="serialization_json.js" type="module"></script>
+	</body>
+</html>

+ 70 - 0
e2e/datachannel/serialization_json.js

@@ -0,0 +1,70 @@
+/**
+ * @type {typeof import('../peerjs').Peer}
+ */
+const Peer = window.Peer;
+
+document.getElementsByTagName("title")[0].innerText =
+	window.location.hash.substring(1);
+
+const checkBtn = document.getElementById("check-btn");
+const sendBtn = document.getElementById("send-btn");
+const receiverIdInput = document.getElementById("receiver-id");
+const connectBtn = document.getElementById("connect-btn");
+const messages = document.getElementById("messages");
+const result = document.getElementById("result");
+const errorMessage = document.getElementById("error-message");
+
+const peer = new Peer();
+const received = [];
+/**
+ * @type {import('../peerjs').DataConnection}
+ */
+let dataConnection;
+peer
+	.once("open", (id) => {
+		messages.textContent = `Your Peer ID: ${id}`;
+	})
+	.once("error", (error) => {
+		errorMessage.textContent = error;
+	})
+	.once("connection", (connection) => {
+		dataConnection = connection;
+		dataConnection.on("data", (data) => {
+			console.log(data);
+			received.push(data);
+		});
+		dataConnection.once("close", () => {
+			messages.textContent = "Closed!";
+		});
+	});
+
+connectBtn.addEventListener("click", () => {
+	const receiverId = receiverIdInput.value;
+	if (receiverId) {
+		dataConnection = peer.connect(receiverId, { serialization: "json" });
+		dataConnection.once("open", () => {
+			messages.textContent = "Connected!";
+		});
+	}
+});
+
+checkBtn.addEventListener("click", async () => {
+	try {
+		window.check(received);
+		result.textContent = "Success!";
+	} catch (e) {
+		result.textContent = "Failed!";
+		errorMessage.textContent = JSON.stringify(e.message);
+	} finally {
+		messages.textContent = "Checked!";
+	}
+});
+
+sendBtn.addEventListener("click", () => {
+	dataConnection.once("error", (err) => {
+		errorMessage.innerText = err.toString();
+	});
+	window.send(dataConnection);
+	dataConnection.close({ flush: true });
+	messages.textContent = "Sent!";
+});

+ 31 - 0
e2e/datachannel/serialization_json.spec.ts

@@ -0,0 +1,31 @@
+import P from "./serialization.page.js";
+import { browser, expect } from "@wdio/globals";
+
+const serializationTest = (testFile: string) => async () => {
+	await P.open(testFile, true);
+	await P.waitForMessage("Your Peer ID: ");
+	const bobId = (await P.messages.getText()).split("Your Peer ID: ")[1];
+	await browser.switchWindow("Alice");
+	await P.waitForMessage("Your Peer ID: ");
+	await P.receiverId.setValue(bobId);
+	await P.connectBtn.click();
+	await P.waitForMessage("Connected!");
+	await P.sendBtn.click();
+	await P.waitForMessage("Sent!");
+	await browser.switchWindow("Bob");
+	await P.waitForMessage("Closed!");
+	await P.checkBtn.click();
+	await P.waitForMessage("Checked!");
+
+	await expect(await P.errorMessage.getText()).toBe("");
+	await expect(await P.result.getText()).toBe("Success!");
+};
+describe("DataChannel:JSON", () => {
+	beforeAll(async () => {
+		await P.init();
+	});
+	it("should transfer numbers", serializationTest("./numbers.js"));
+	it("should transfer strings", serializationTest("./strings_json.js"));
+	it("should transfer objects", serializationTest("./objects.js"));
+	it("should transfer arrays", serializationTest("./arrays_json.js"));
+});

+ 17 - 0
e2e/datachannel/strings.js

@@ -0,0 +1,17 @@
+import { strings, long_string } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	expect(received).to.deep.equal([long_string, ...strings]);
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	dataConnection.send(long_string);
+	for (const string of strings) {
+		dataConnection.send(string);
+	}
+};
+window["connect-btn"].disabled = false;

+ 19 - 0
e2e/datachannel/strings_json.js

@@ -0,0 +1,19 @@
+/**
+ * JSON transfer does not chunk, large_string is too large to send
+ */
+import { strings, long_string } from "../data.js";
+import { expect } from "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs";
+
+/** @param {unknown[]} received */
+window.check = (received) => {
+	expect(received).to.deep.equal(strings);
+};
+/**
+ * @param {import("../peerjs").DataConnection} dataConnection
+ */
+window.send = (dataConnection) => {
+	for (const string of strings) {
+		dataConnection.send(string);
+	}
+};
+window["connect-btn"].disabled = false;

+ 3 - 0
e2e/package.json

@@ -0,0 +1,3 @@
+{
+	"type": "module"
+}

+ 26 - 0
e2e/style.css

@@ -0,0 +1,26 @@
+body {
+	font-family: Arial, sans-serif;
+	max-width: 800px;
+	margin: 0 auto;
+	padding: 20px;
+}
+
+#inputs {
+	display: flex;
+	flex-wrap: wrap;
+	gap: 10px;
+	align-items: center;
+}
+
+button {
+	background-color: #007bff;
+	color: white;
+	border: none;
+	padding: 8px 16px;
+	border-radius: 4px;
+	cursor: pointer;
+}
+
+button:hover {
+	background-color: #0056b3;
+}

+ 70 - 0
e2e/tsconfig.json

@@ -0,0 +1,70 @@
+{
+	"compilerOptions": {
+		/* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+		/* Basic Options */
+		// "incremental": true,                   /* Enable incremental compilation */
+		"target": "ES2022" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
+		"module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
+		// "lib": [],                             /* Specify library files to be included in the compilation. */
+		// "allowJs": true,                       /* Allow javascript files to be compiled. */
+		// "checkJs": true,                       /* Report errors in .js files. */
+		// "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
+		// "declaration": true,                   /* Generates corresponding '.d.ts' file. */
+		// "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
+		// "sourceMap": true,                     /* Generates corresponding '.map' file. */
+		// "outFile": "./",                       /* Concatenate and emit output to single file. */
+		// "outDir": "./",                        /* Redirect output structure to the directory. */
+		// "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+		// "composite": true,                     /* Enable project compilation */
+		// "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
+		// "removeComments": true,                /* Do not emit comments to output. */
+		// "noEmit": true,                        /* Do not emit outputs. */
+		// "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
+		// "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+		// "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+
+		/* Strict Type-Checking Options */
+		"strict": true /* Enable all strict type-checking options. */,
+		// "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
+		// "strictNullChecks": true,              /* Enable strict null checks. */
+		// "strictFunctionTypes": true,           /* Enable strict checking of function types. */
+		// "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+		// "strictPropertyInitialization": true,  /* Enable strict checking of property initialization in classes. */
+		// "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
+		// "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
+
+		/* Additional Checks */
+		// "noUnusedLocals": true,                /* Report errors on unused locals. */
+		// "noUnusedParameters": true,            /* Report errors on unused parameters. */
+		// "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
+		// "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
+		// "noUncheckedIndexedAccess": true,      /* Include 'undefined' in index signature results */
+
+		/* Module Resolution Options */
+		"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
+		// "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
+		// "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+		// "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
+		// "typeRoots": [],                       /* List of folders to include type definitions from. */
+		"types": ["node", "@wdio/globals/types", "@wdio/jasmine-framework"],
+		"allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
+		// "esModuleInterop": true,               /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+		// "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
+		// "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */
+
+		/* Source Map Options */
+		// "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+		// "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
+		// "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
+		// "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+
+		/* Experimental Options */
+		// "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
+		// "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
+
+		/* Advanced Options */
+		"skipLibCheck": true /* Skip type checking of declaration files. */,
+		"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
+	}
+}

+ 11 - 0
e2e/types.d.ts

@@ -0,0 +1,11 @@
+/* eslint no-unused-vars: 0 */
+
+declare module "https://esm.sh/v126/chai@4.3.7/X-dHMvZXhwZWN0/es2021/chai.bundle.mjs" {
+	export = chai;
+}
+
+interface Window {
+	"connect-btn": HTMLButtonElement;
+	send: (dataConnection: import("../../peerjs").DataConnection) => void;
+	check: (received: unknown[]) => void;
+}

+ 71 - 0
e2e/wdio.bstack.conf.ts

@@ -0,0 +1,71 @@
+import { config as sharedConfig } from "./wdio.shared.conf.js";
+
+export const config: WebdriverIO.Config = {
+	...sharedConfig,
+	...{
+		user: process.env.BROWSERSTACK_USERNAME,
+		key: process.env.BROWSERSTACK_ACCESS_KEY,
+		hostname: "hub.browserstack.com",
+		services: [
+			[
+				"browserstack",
+				{
+					browserstackLocal: true,
+				},
+			],
+		],
+		capabilities: [
+			{
+				browserName: "Edge",
+				"bstack:options": {
+					os: "Windows",
+					osVersion: "11",
+					browserVersion: "81",
+					localIdentifier: process.env.BROWSERSTACK_LOCAL_IDENTIFIER,
+				},
+			},
+			{
+				browserName: "Firefox",
+				"bstack:options": {
+					os: "Windows",
+					osVersion: "7",
+					browserVersion: "80.0",
+					localIdentifier: process.env.BROWSERSTACK_LOCAL_IDENTIFIER,
+				},
+			},
+			{
+				browserName: "Safari",
+				"bstack:options": {
+					browserVersion: "latest",
+					os: "OS X",
+					osVersion: "Big Sur",
+					localIdentifier: process.env.BROWSERSTACK_LOCAL_IDENTIFIER,
+				},
+			},
+			// {
+			// 	browserName: 'Safari',
+			// 	'bstack:options': {
+			// 		browserVersion: 'latest',
+			// 		os: 'OS X',
+			// 		osVersion: 'Monterey'
+			// 	}
+			// },
+			// {
+			// 	browserName: 'Chrome',
+			// 	'bstack:options': {
+			// 		browserVersion: 'latest',
+			// 		os: 'Windows',
+			// 		osVersion: '11'
+			// 	}
+			// },
+			// {
+			// 	browserName: 'Firefox',
+			// 	'bstack:options': {
+			// 		browserVersion: 'latest',
+			// 		os: 'OS X',
+			// 		osVersion: 'Ventura'
+			// 	}
+			// }
+		],
+	},
+};

+ 23 - 0
e2e/wdio.local.conf.ts

@@ -0,0 +1,23 @@
+import { config as sharedConfig } from "./wdio.shared.conf.js";
+
+export const config: WebdriverIO.Config = {
+	runner: "local",
+	...sharedConfig,
+	services: ["geckodriver"],
+	...{
+		capabilities: [
+			{
+				browserName: "chrome",
+				"wdio:devtoolsOptions": {
+					headless: true,
+				},
+			},
+			{
+				browserName: "firefox",
+				"moz:firefoxOptions": {
+					args: ["-headless"],
+				},
+			},
+		],
+	},
+};

+ 250 - 0
e2e/wdio.shared.conf.ts

@@ -0,0 +1,250 @@
+import url from "node:url";
+import path from "node:path";
+
+const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
+
+export const config: Omit<WebdriverIO.Config, "capabilities"> = {
+	injectGlobals: false,
+	//
+	// ====================
+	// Runner Configuration
+	// ====================
+	//
+	// WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
+	// on a remote machine).
+	// runner: 'local',
+	//
+	// ==================
+	// Specify Test Files
+	// ==================
+	// Define which test specs should run. The pattern is relative to the directory
+	// from which `wdio` was called. Notice that, 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: ["./**/*.spec.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: 5,
+	//
+	// ===================
+	// Test Configurations
+	// ===================
+	// Define all options that are relevant for the WebdriverIO instance here
+	//
+	// Level of logging verbosity: trace | debug | info | warn | error | silent
+	logLevel: "trace",
+	outputDir: path.resolve(__dirname, "logs"),
+	//
+	// Set specific log levels per logger
+	// loggers:
+	// - webdriver, webdriverio
+	// - @wdio/applitools-service, @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
+	// - @wdio/mocha-framework, @wdio/jasmine-framework
+	// - @wdio/local-runner, @wdio/lambda-runner
+	// - @wdio/sumologic-reporter
+	// - @wdio/cli, @wdio/config, @wdio/sync, @wdio/utils
+	// Level of logging verbosity: trace | debug | info | warn | error | silent
+	// logLevels: {
+	//     webdriver: 'info',
+	//     '@wdio/applitools-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: "http://localhost:3000",
+	//
+	// Default timeout for all waitFor* commands.
+	waitforTimeout: 10000,
+	//
+	// Default timeout in milliseconds for request
+	// if browser driver or grid doesn't send response
+	connectionRetryTimeout: 90000,
+	//
+	// Default request retries count
+	connectionRetryCount: 3,
+	//
+	// Framework you want to run your specs with.
+	// The following are supported: Mocha, Jasmine, and Cucumber
+	// see also: https://webdriver.io/docs/frameworks.html
+	//
+	// Make sure you have the wdio adapter package for the specific framework installed
+	// before running any tests.
+	framework: "jasmine",
+	//
+	// The number of times to retry the entire specfile when it fails as a whole
+	// specFileRetries: 1,
+	//
+	// Whether or not retried specfiles 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.html
+	reporters: ["spec"],
+	//
+	// Options to be passed to Jasmine.
+	jasmineOpts: {
+		// Jasmine default timeout
+		defaultTimeoutInterval: 60000,
+		//
+		// The Jasmine framework allows interception of each assertion in order to log the state of the application
+		// or website depending on the result. For example, it is pretty handy to take a screenshot every time
+		// an assertion fails.
+		// expectationResultHandler: function(passed, assertion) {
+		// do something
+		// }
+	},
+	//
+	// =====
+	// 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  {[type]} caps     object containing capabilities for session that will be spawn in the worker
+	 * @param  {[type]} specs    specs to be run in the worker process
+	 * @param  {[type]} args     object that will be merged with the main configuration once worker is initialised
+	 * @param  {[type]} execArgv list of string arguments passed to the worker process
+	 */
+	// onWorkerStart: function (cid, caps, specs, args, execArgv) {
+	// },
+	/**
+	 * 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
+	 */
+	// beforeSession: function (config, capabilities, specs) {
+	// },
+	/**
+	 * 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
+	 */
+	// 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).
+	 */
+	// 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 - 0
jest.config.cjs

@@ -4,4 +4,5 @@ module.exports = {
 	transform: {
 		"^.+\\.(t|j)sx?$": ["@swc/jest"],
 	},
+	modulePathIgnorePatterns: ["e2e"],
 };

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 868 - 72
package-lock.json


+ 16 - 3
package.json

@@ -151,7 +151,7 @@
 	},
 	"scripts": {
 		"contributors": "git-authors-cli --print=false && prettier --write package.json && git add package.json package-lock.json && git commit -m \"chore(contributors): update and sort contributors list\"",
-		"check": "tsc --noEmit",
+		"check": "tsc --noEmit && tsc -p e2e/tsconfig.json --noEmit",
 		"watch": "parcel watch",
 		"build": "rm -rf dist && parcel build",
 		"prepublishOnly": "npm run build",
@@ -159,7 +159,9 @@
 		"test:watch": "jest --watch",
 		"coverage": "jest --coverage --collectCoverageFrom=\"./lib/**\"",
 		"format": "prettier --write .",
-		"semantic-release": "semantic-release"
+		"semantic-release": "semantic-release",
+		"e2e": "wdio run e2e/wdio.local.conf.ts",
+		"e2e:bstack": "wdio run e2e/wdio.bstack.conf.ts"
 	},
 	"devDependencies": {
 		"@parcel/config-default": "^2.8.1",
@@ -170,6 +172,15 @@
 		"@semantic-release/git": "^10.0.1",
 		"@swc/core": "^1.3.27",
 		"@swc/jest": "^0.2.24",
+		"@types/jasmine": "^4.3.4",
+		"@wdio/browserstack-service": "^8.11.2",
+		"@wdio/cli": "^8.11.2",
+		"@wdio/globals": "^8.11.2",
+		"@wdio/jasmine-framework": "^8.11.2",
+		"@wdio/local-runner": "^8.11.2",
+		"@wdio/spec-reporter": "^8.11.2",
+		"@wdio/types": "^8.10.4",
+		"http-server": "^14.1.1",
 		"jest": "^29.3.1",
 		"jest-environment-jsdom": "^29.3.1",
 		"mock-socket": "^9.0.0",
@@ -177,7 +188,9 @@
 		"parcel-transformer-tsc-sourcemaps": "^1.0.2",
 		"prettier": "^2.6.2",
 		"semantic-release": "^20.0.0",
-		"typescript": "^4.5.5"
+		"ts-node": "^10.9.1",
+		"typescript": "^4.5.5",
+		"wdio-geckodriver-service": "^5.0.1"
 	},
 	"dependencies": {
 		"@swc/helpers": "^0.4.0",

+ 2 - 1
tsconfig.json

@@ -9,5 +9,6 @@
 		"isolatedModules": true,
 		"resolveJsonModule": true,
 		"lib": ["es2020", "dom"]
-	}
+	},
+	"exclude": ["node_modules", "dist", "e2e"]
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است