Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/e2e testing #57

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/lint-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ jobs:

- name: Test
run: pnpm test

- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps

- name: UI Integration Tests
run: pnpm test:e2e
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ A monorepo is a single repository that contains multiple projects. This allows u

This repository is an amalgamation of all the tools and applications that make DiceDB fun and easy to use in the real world. The name is a nod to this amalgamation, and inspired by the [alloy](https://en.wikipedia.org/wiki/Alloy).


## What's inside?

This monorepo includes the following packages/apps:
Expand All @@ -29,6 +28,7 @@ This monorepo includes the following packages/apps:
### Prerequisites

Ensure you have the following installed:

- node.js (v18.17.0 or later)
- pnpm (v9.10.0 or later)

Expand All @@ -43,8 +43,6 @@ npm install -g [email protected]

> If you're unfamiliar with pnpm, it’s an alternative package manager that is faster and more efficient than npm. Learn more about pnpm [here](https://pnpm.io/).



### Installation

Clone the repository and install the dependencies:
Expand Down Expand Up @@ -102,7 +100,6 @@ These commands will not only start the development server for the package reques

> We also have a `pnpm dev:playground` alias that does the same thing as `pnpm dev --filter @dicedb/playground-web` for convenience.


### Testing

To run tests for all apps and packages, run the following command:
Expand All @@ -121,7 +118,13 @@ cd alloy
pnpm test:watch
```

### Integration Test

To run E2E test, run the following command:

```
pnpm test:e2e
```

### Formatting

Expand All @@ -144,6 +147,7 @@ pnpm lint
## The Monorepo Structure

The monorepo is divided into 3 main directories:

- `apps`: contains all the applications i.e. deployable units
- `packages`: contains all the packages i.e. reusable code across the apps
- `tooling`: contains all the configurations and tooling used across the monorepo
Expand Down
5 changes: 5 additions & 0 deletions apps/playground-web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts

/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
2 changes: 1 addition & 1 deletion apps/playground-web/components/Shell/Shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default function Shell({ decreaseCommandsLeft }: ShellProps) {
{output.map((line, index) => (
<div
key={index}
data-testid="terminal-output"
data-testid={`terminal-output-${index + 1}`}
className="text-white p-1"
>
{line}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('Shell Component', () => {
const { cliInputElement, user, getByTestId } = setupTest();

await user.type(cliInputElement, 'EXEC{enter}');
const terminalOutputElement = getByTestId('terminal-output');
const terminalOutputElement = getByTestId('terminal-output-1');
expect(terminalOutputElement).toHaveTextContent(
"(error) ERR unknown command 'EXEC'",
);
Expand Down
2 changes: 1 addition & 1 deletion apps/playground-web/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ services:
depends_on:
- dicedb
environment:
- DICE_ADDR=dicedb:7379
- DICEDB_ADDR=dicedb:7379

frontend:
build:
Expand Down
12 changes: 6 additions & 6 deletions apps/playground-web/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import nextJest from "next/jest.js";
import nextJest from 'next/jest.js';

const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: "./",
dir: './',
});

// Add any custom config to be passed to Jest
/**
* @type {import('@jest').Config}
*/
const config = {
coverageProvider: "v8",
testEnvironment: "jsdom",
coverageProvider: 'v8',
testEnvironment: 'jsdom',
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
'^@/(.*)$': '<rootDir>/$1',
},
// Add more setup options before each test is run
setupFilesAfterEnv: ["<rootDir>/jest.setup.mjs"],
setupFilesAfterEnv: ['<rootDir>/jest.setup.mjs'],
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
Expand Down
7 changes: 5 additions & 2 deletions apps/playground-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
"lint": "eslint . --ext js,jsx,ts,tsx",
"type-check": "tsc --noEmit",
"prettier:format": "prettier -c ../../.prettierrc --write \"**/*.{js,jsx,ts,tsx,json,css}\"",
"test": "jest",
"test": "jest --testPathIgnorePatterns=\"/tests/\"",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage"
"test:coverage": "jest --coverage",
"test:e2e": "npx playwright test",
"test:e2e-report": "npx playwright show-report"
},
"dependencies": {
"@emotion/react": "^11.13.3",
Expand All @@ -32,6 +34,7 @@
"@dicedb/ui": "workspace:*"
},
"devDependencies": {
"@playwright/test": "^1.47.2",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
Expand Down
47 changes: 47 additions & 0 deletions apps/playground-web/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,

Check warning on line 8 in apps/playground-web/playwright.config.ts

View workflow job for this annotation

GitHub Actions / Build and Test

CI is not listed as a dependency in the root turbo.json or workspace () turbo.json
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,

Check warning on line 10 in apps/playground-web/playwright.config.ts

View workflow job for this annotation

GitHub Actions / Build and Test

CI is not listed as a dependency in the root turbo.json or workspace () turbo.json
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,

Check warning on line 12 in apps/playground-web/playwright.config.ts

View workflow job for this annotation

GitHub Actions / Build and Test

CI is not listed as a dependency in the root turbo.json or workspace () turbo.json
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
},

webServer: {
command: 'npm run dev',
url: 'http://127.0.0.1:3000',
reuseExistingServer: !process.env.CI,

Check warning on line 24 in apps/playground-web/playwright.config.ts

View workflow job for this annotation

GitHub Actions / Build and Test

CI is not listed as a dependency in the root turbo.json or workspace () turbo.json
},

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

{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
timeout: 30000,
},

{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
timeout: 30000,
},
],
});
104 changes: 104 additions & 0 deletions apps/playground-web/tests/playground.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { test, expect } from '@playwright/test';
import type { Page } from '@playwright/test';

const runCommand = async (page: Page, cmd: string) => {
const cmdInput = page.getByTestId('shell-input');
await cmdInput.fill(cmd);
await page.keyboard.press('Enter');
};

test.describe('[Playground Component]', () => {
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:3000');
const cmdInput = page.getByTestId('shell-input');
await expect(cmdInput).toBeVisible();
});

test('should execute SET command properly', async ({ page }) => {
let outputIdx = 0;

// Happy case
await runCommand(page, 'SET foo bar');
// Adding 2 to outputIndex after each command execution
// Reason: 2 items are added to output after each execution, 1st is command itself and 2nd is its result
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'OK',
);

// Error case: SET with wrong number of arguments
await runCommand(page, 'SET foo');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
"(error) ERR wrong number of arguments for 'set' command",
);
});

test('should execute GET command properly', async ({ page }) => {
let outputIdx = 0;

// Happy case
await runCommand(page, 'SET foo bar');
outputIdx += 2;
await runCommand(page, 'GET foo');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();

await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'bar',
);

// Error case for wrong key get
await runCommand(page, 'GET foo1');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'(nil)',
);

// Error case: GET with wrong number of arguments
await runCommand(page, 'GET foo bar');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
"(error) ERR wrong number of arguments for 'get' command",
);
});

test('should execute DEL command properly', async ({ page }) => {
let outputIdx = 0;

// Happy case
await runCommand(page, 'SET foo bar');
outputIdx += 2;
await runCommand(page, 'GET foo');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'bar',
);
await runCommand(page, 'DEL foo');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'1',
);
await runCommand(page, 'GET foo');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
// Getting back the deleted key should return (nil) output
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'(nil)',
);

// Error case: DEL key which is not present
await runCommand(page, 'DEL bar');
outputIdx += 2;
await page.getByTestId(`terminal-output-${outputIdx}`).waitFor();
await expect(page.getByTestId(`terminal-output-${outputIdx}`)).toHaveText(
'0',
);
});
});
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"lint": "turbo lint",
"format": "prettier -c ./.prettierrc --write \"**/*.{js,jsx,ts,tsx,json,css}\"",
"check:format": "prettier -c ./.prettierrc \"**/*.{js,jsx,ts,tsx,json,css}\"",
"test": "turbo test"
"test": "turbo test",
"test:e2e": "turbo test:e2e"
},
"devDependencies": {
"prettier": "^3.2.5",
Expand Down
Loading
Loading