Skip to content

Commit

Permalink
RSDK-851 rpc js tests (#221)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Cousins <[email protected]>
  • Loading branch information
maximpertsov and mcous authored Dec 5, 2023
1 parent bfd3901 commit ab8a226
Show file tree
Hide file tree
Showing 11 changed files with 300 additions and 10 deletions.
21 changes: 20 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,26 @@ jobs:
exit 1
fi
- name: Test
- name: Test js library
run: sudo -u testbot bash -lc 'CI=true make test-web'

- if: failure()
run: |
pwd
ls rpc
ls rpc/examples
ls rpc/examples/echo/
ls rpc/examples/echo/playwright-report
- if: failure()
name: Upload js test report
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: rpc/examples/echo/playwright-report
retention-days: 30

- name: Test go library
env:
TEST_MONGODB_URI: ${{ secrets.TEST_MONGODB_URI }}
MONGODB_TEST_OUTPUT_URI: ${{ secrets.MONGODB_TEST_OUTPUT_URI }}
Expand Down
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,14 @@ lint-go: tool-install
cover: tool-install
PATH=$(PATH_WITH_TOOLS) ./etc/test.bash cover

test: tool-install
test: test-go test-web

test-go: tool-install
PATH=$(PATH_WITH_TOOLS) ./etc/test.bash

test-web:
$(MAKE) -C rpc/examples/echo test-run-server

# examples

example-echo/%: build-web
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ For example, try running a simple echo server with:
make example-echo/run-server
```

### Automated Web Browser Tests

You can web browser tests locally with the following commands:

```
make build-web # one time step
make test-web
```

## Windows Support

Windows 10 22H2 and up.
Expand Down
5 changes: 5 additions & 0 deletions rpc/examples/echo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
8 changes: 8 additions & 0 deletions rpc/examples/echo/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ build:
run-server: build
go run server/cmd/main.go -instance-name=echo-server

.PHONY: install-playwright
install-playwright:
npm install
npx playwright install --with-deps

test-run-server: build install-playwright
npx playwright test

run-client:
go run client/main.go -host=echo-server

Expand Down
26 changes: 18 additions & 8 deletions rpc/examples/echo/frontend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ declare global {
}
}

function createElemForResponse(text: string, method: string, type: string) {
const selector = `[data-testid="${type}-${method}"]`;
const elem = document.querySelector(selector);
if (!elem) {
throw new Error(`expecting to find selector '${selector}'`);
}
const inner = document.createElement("div");
inner.setAttribute("data-testid", "message");
inner.innerText = text;
elem.appendChild(inner);
}

async function getClients() {
const webrtcHost = window.webrtcHost;
const opts: DialOptions = {
Expand Down Expand Up @@ -45,21 +57,19 @@ async function getClients() {
opts.webrtcOptions!.signalingExternalAuthToEntity = opts.externalAuthToEntity;
}

console.log("WebRTC")
const webRTCConn = await dialWebRTC(thisHost, webrtcHost, opts);
const webrtcClient = new EchoServiceClient(webrtcHost, { transport: webRTCConn.transportFactory });
await doEchos(webrtcClient);
await renderResponses(webrtcClient, "wrtc");

console.log("Direct") // bi-di may not work
const directTransport = await dialDirect(thisHost, opts);
const directClient = new EchoServiceClient(thisHost, { transport: directTransport });
await doEchos(directClient);
await renderResponses(directClient, "direct");
}
getClients().catch(e => {
console.error("error getting clients", e);
});

async function doEchos(client: EchoServiceClient) {
async function renderResponses(client: EchoServiceClient, method: string) {
const echoRequest = new EchoRequest();
echoRequest.setMessage("hello");

Expand All @@ -75,7 +85,7 @@ async function doEchos(client: EchoServiceClient) {
pReject(err);
return
}
console.log(resp.toObject());
createElemForResponse(resp.getMessage(), method, "unary");
pResolve(resp);
});
await done;
Expand All @@ -89,7 +99,7 @@ async function doEchos(client: EchoServiceClient) {
});
const multiStream = client.echoMultiple(echoMultipleRequest);
multiStream.on("data", (message: EchoMultipleResponse) => {
console.log(message.toObject());
createElemForResponse(message.getMessage(), method, "multi");
});
multiStream.on("end", ({ code, details }: { code: number, details: string, metadata: grpc.Metadata }) => {
if (code !== 0) {
Expand All @@ -115,7 +125,7 @@ async function doEchos(client: EchoServiceClient) {
let msgCount = 0;
bidiStream.on("data", (message: EchoMultipleResponse) => {
msgCount++
console.log(message.toObject());
createElemForResponse(message.getMessage(), method, "bidi");
if (msgCount == 3) {
pResolve(undefined);
}
Expand Down
91 changes: 91 additions & 0 deletions rpc/examples/echo/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions rpc/examples/echo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "echo",
"version": "1.0.0",
"description": "This example server demonstrates how to run gRPC accessible via `grpc`, `grpc-web`, `grpc-gateway`, and `grpc-over-webrtc` all on the same port while hosting other HTTP services.",
"main": "index.js",
"scripts": {},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.39.0",
"@types/node": "^20.9.0"
}
}
75 changes: 75 additions & 0 deletions rpc/examples/echo/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { defineConfig, devices } from "@playwright/test";

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 1 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : 3,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [["html", { open: "never" }]],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:8080",

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: process.env.CI ? "on-first-retry" : "retain-on-failure",
},

/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},

{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},

// TODO(RSDK-4494): fix safari tests
// {
// name: "webkit",
// use: { ...devices["Desktop Safari"] },
// },

/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },

/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ..devices['Desktop Chrome'], channel: 'chrome' },
// },
],

/* Run your local dev server before starting the tests */
webServer: {
command: "make run-server",
url: `http://127.0.0.1:8080`,
reuseExistingServer: !process.env.CI,
},
});
33 changes: 33 additions & 0 deletions rpc/examples/echo/server/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,38 @@
window.accessToken = {{ .AccessToken }}
</script>
<script src="./static/main.js"></script>
<style>
table {
border-collapse: collapse;
}
td, th {
border: 1px solid #999;
padding: 0.5rem;
}
</style>
</head>
<body>
<table>
<tr>
<th></th>
<th>WebRTC</th>
<th>Direct gRPC</th>
</tr>
<tr>
<th>Unary</th>
<td data-testid="unary-wrtc"></td>
<td data-testid="unary-direct"></td>
</tr>
<tr>
<th>Multiple</th>
<td data-testid="multi-wrtc"></td>
<td data-testid="multi-direct"></td>
</tr>
<tr>
<th>BiDi</th>
<td data-testid="bidi-wrtc"></td>
<td data-testid="bidi-direct"></td>
</tr>
</table>
</body>
</html>
21 changes: 21 additions & 0 deletions rpc/examples/echo/tests/echo.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test, expect } from "@playwright/test";

test("receives responses", async ({ page }) => {
await page.goto("/");
const table: [string, string[]][] = [
["unary-wrtc", ["hello"]],
["multi-wrtc", ["h", "e", "l", "l", "o", "?"]],
["bidi-wrtc", ["o", "n", "e", "t", "w", "o"]],
["unary-direct", ["hello"]],
["multi-direct", ["h", "e", "l", "l", "o", "?"]],
// gRPC-web does not yet support bidirectional streaming so we expect to
// only receive a response to our first request.
["bidi-direct", ["o", "n", "e"]],
];

for (const [testID, expected] of table) {
const messages = page.getByTestId(testID).getByTestId("message");
await expect(messages).toHaveCount(expected.length);
await expect(messages).toContainText(expected);
}
});

0 comments on commit ab8a226

Please sign in to comment.