Skip to content

Commit

Permalink
Merge f0c3618 into f437701
Browse files Browse the repository at this point in the history
  • Loading branch information
codesankalp committed Jun 20, 2021
2 parents f437701 + f0c3618 commit 4909e46
Show file tree
Hide file tree
Showing 11 changed files with 365 additions and 21 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,44 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: ${{ runner.os }}-yarn-

- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: 3.7

- name: Installing dependencies
run: |
yarn install
yarn setup
- name: Installing OpenWISP Radius
run: |
git clone https://github.com/openwisp/openwisp-radius/
cd openwisp-radius && pip install -e .
./tests/manage.py migrate
- name: Running OpenWISP Radius
run: cd openwisp-radius && ./tests/manage.py runserver &

- name: Running OpenWISP WiFi Login Pages
run: yarn start &

- name: Tests
run: yarn coverage

- name: geckodriver/firefox
run: |
echo "geckodriver/firefox"
which geckodriver
geckodriver --version
which firefox
firefox --version
- name: Browser Tests
run: |
export OPENWISP_RADIUS_PATH=$(pwd)/openwisp-radius
yarn browser-test
- name: Coveralls
uses: coverallsapp/github-action@master
with:
Expand Down
48 changes: 36 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,28 @@ To verify all the dependencies were successfully installed,
try to run the tests with the following command:

```
yarn test
yarn test # headless tests
```

##### Browser based tests

Prerequisites for running browser-based tests:

1. [Gecko driver](https://github.com/mozilla/geckodriver/releases/) needs to be installed.
2. Running instances of openwisp-radius and
openwisp-wifi-login-pages is required.
3. `OPENWIPS_RADIUS_PATH` environment variable is needed to initialize
data while running browser test. This can be set using the following command:
```
export OPENWISP_RADIUS_PATH=< PATH TO OPENWISP RADIUS DIRECTORY >
```
4. If a virtual environment is used to run openwisp-radius then
this needs to be activated before running browser tests.

After doing all the prerequisites, run browser based tests using the following command:

```
yarn browser-test
```

#### Setup
Expand Down Expand Up @@ -155,17 +176,20 @@ you can use the default sample captive portal login and logout URLs.
List of yarn commands:

```
$ yarn start # Run the app (runs both, client and server)
$ yarn setup # Discover Organization configs and generate config.json and asset directories
$ yarn add-org # Add new Organization configuration
$ yarn build # Build the app
$ yarn server # Run server
$ yarn client # Run client
$ yarn coveralls # Run coveralls
$ yarn lint # Run ESLint
$ yarn lint:fix # Run ESLint with automatically fix problems option
$ yarn test # Run tests
$ yarn -- -u # Update Jest Snapshots
$ yarn start # Run the app (runs both, client and server)
$ yarn setup # Discover Organization configs and generate config.json and asset directories
$ yarn add-org # Add new Organization configuration
$ yarn build # Build the app
$ yarn server # Run server
$ yarn client # Run client
$ yarn coveralls # Run coveralls
$ yarn coverage # Run tests and generate coverage files
$ yarn lint # Run ESLint
$ yarn lint:fix # Run ESLint with automatically fix problems option
$ yarn format # Run formatters to format the code
$ yarn test # Run tests
$ yarn browser-test # Run browser based selenium tests
$ yarn -- -u # Update Jest Snapshots
```

#### Using custom ports
Expand Down
26 changes: 26 additions & 0 deletions browser-test/clear_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python
import os
import sys
import json

project_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
browser_test_path = os.path.join(project_path, 'browser-test')
test_data_file = open(os.path.join(browser_test_path, 'testData.json'))
test_data = json.loads(test_data_file.read())
test_data_file.close()

OPENWISP_RADIUS_PATH = os.getenv('OPENWISP_RADIUS_PATH', '')

if OPENWISP_RADIUS_PATH == '':
print('OPENWISP_RADIUS_PATH is needed for initializing data.')
sys.exit(0)

test_user_email = test_data['testuser']['email']
print(
os.popen(
f'''
echo "User.objects.get(username='{test_user_email}').delete()"\
| {OPENWISP_RADIUS_PATH}/tests/manage.py shell_plus
'''
).read()
)
30 changes: 30 additions & 0 deletions browser-test/initialize_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env python
import os
import sys
import json

project_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
browser_test_path = os.path.join(project_path, 'browser-test')
test_data_file = open(os.path.join(browser_test_path, 'testData.json'))
test_data = json.loads(test_data_file.read())
test_data_file.close()

OPENWISP_RADIUS_PATH = os.getenv('OPENWISP_RADIUS_PATH', '')

if OPENWISP_RADIUS_PATH == '':
print('OPENWISP_RADIUS_PATH is needed for initializing data.')
sys.exit(0)

test_user_email = test_data['testuser']['email']
test_user_password = test_data['testuser']['password']
test_user_organization = test_data['testuser']['organization']
print(
os.popen(
f'''
echo "user=User.objects.create_user(username='{test_user_email}', password='{test_user_password}', email='{test_user_email}')\n
org = Organization.objects.get(name='{test_user_organization}')\n
OrganizationUser.objects.create(organization=org, user=user)"\
| {OPENWISP_RADIUS_PATH}/tests/manage.py shell_plus
'''
).read()
)
71 changes: 71 additions & 0 deletions browser-test/login.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {Builder, By, until} from "selenium-webdriver";
import {
getDriver,
getElementByXPath,
urls,
initialData,
executeCommand,
} from "./utils";

const firefox = require("selenium-webdriver/firefox");

describe("Selenium tests for <Login />", () => {
let driver;
beforeAll(async () => {
jest.setTimeout(30000);
await executeCommand("./browser-test/initialize_data.py", () => {});
driver = await getDriver(Builder, new firefox.Options().headless());
});

afterAll(async () => {
await executeCommand("./browser-test/clear_data.py", () => {});
driver.close();
});

it("should render login page and submit login form", async () => {
await driver.get(urls.login);
const data = initialData();
const username = await getElementByXPath(
driver,
"//INPUT[@id='username']",
until,
By,
);
username.sendKeys(data.testuser.email);

const password = await getElementByXPath(
driver,
"//INPUT[@id='password']",
until,
By,
);
password.sendKeys(data.testuser.password);

const submitBtn = await getElementByXPath(
driver,
"/html/body/div[1]/div[2]/div[3]/div/form/div[4]/input",
until,
By,
);
submitBtn.click();

await getElementByXPath(driver, "//DIV[@id='status']", until, By);
const emailElement = await getElementByXPath(
driver,
"(//SPAN)[2]",
until,
By,
);
expect(await emailElement.getText()).toEqual(data.testuser.email);

const successToastDiv = await getElementByXPath(
driver,
"//DIV[@role='alert']",
until,
By,
);
await driver.wait(until.elementIsVisible(successToastDiv));
await driver.wait(until.urlContains("status"), 10000);
expect(await successToastDiv.getText()).toEqual("Login successful");
});
});
70 changes: 70 additions & 0 deletions browser-test/registration.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {Builder, By, until} from "selenium-webdriver";
import {
getDriver,
getElementByXPath,
urls,
initialData,
executeCommand,
} from "./utils";

const firefox = require("selenium-webdriver/firefox");

describe("Selenium tests for <Register />", () => {
let driver;
beforeAll(async () => {
jest.setTimeout(30000);
driver = await getDriver(Builder, new firefox.Options().headless());
});

afterAll(async () => {
await executeCommand("./browser-test/clear_data.py", () => {});
driver.close();
});

it("should render registration page and submit registration form", async () => {
await driver.get(urls.registration);
const data = initialData();
const username = await getElementByXPath(
driver,
"//INPUT[@id='email']",
until,
By,
);
username.sendKeys(data.testuser.email);

const password = await getElementByXPath(
driver,
"//INPUT[@id='password']",
until,
By,
);
password.sendKeys(data.testuser.password);

const confirmPassword = await getElementByXPath(
driver,
"//INPUT[@id='password-confirm']",
until,
By,
);
confirmPassword.sendKeys(data.testuser.password);

const submitBtn = await getElementByXPath(
driver,
"//INPUT[@type='submit']",
until,
By,
);
submitBtn.click();

await getElementByXPath(driver, "//DIV[@id='status']", until, By);
const successToastDiv = await getElementByXPath(
driver,
"//DIV[@role='alert']",
until,
By,
);
await driver.wait(until.elementIsVisible(successToastDiv));
await driver.wait(until.urlContains("status"), 10000);
expect(await successToastDiv.getText()).toEqual("Registration success");
});
});
7 changes: 7 additions & 0 deletions browser-test/testData.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"testuser": {
"email": "testuser@openwisp.org",
"password": "testuser",
"organization": "default"
}
}
39 changes: 39 additions & 0 deletions browser-test/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {exec} from "child_process";
import testData from "./testData.json";

const waitTime = 20000;
const orgSlug = "default";

export const getDriver = async (Builder, options) => {
const driver = await new Builder()
.forBrowser("firefox")
.setFirefoxOptions(options)
.build();
return driver;
};

export const getElementByXPath = async (driver, xpath, until, By) => {
const el = await driver.wait(until.elementLocated(By.xpath(xpath)), waitTime);
driver.wait(until.stalenessOf(el), waitTime);
return el;
};

export const sleep = async (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};

export const initialData = () => testData;

export const executeCommand = async (command, callback) => {
await exec(command, (error, stdout, stderr) => {
if (error) return callback(error.message);
if (stderr) return callback(stderr);
return callback(stdout);
});
};

export const urls = {
registration: `http://0.0.0.0:8080/${orgSlug}/registration`,
login: `http://0.0.0.0:8080/${orgSlug}/login`,
status: `http://0.0.0.0:8080/${orgSlug}/status`,
};
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,8 @@ describe("Test <OrganizationWrapper /> routes", () => {
let props;
let wrapper;
const defaultConfig = getConfig("default");
const {
components,
languages,
privacy_policy,
terms_and_conditions,
} = defaultConfig;
const {components, languages, privacy_policy, terms_and_conditions} =
defaultConfig;

const mapRoutes = (component) => {
const pathMap = {};
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"prettier": "^2.2.0",
"react-test-renderer": "^16.13.1",
"redux-mock-store": "^1.5.4",
"selenium-webdriver": "^4.0.0-beta.4",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^4.2.3",
"typescript": "^4.1.2",
Expand All @@ -93,7 +94,7 @@
"scripts": {
"build": "npm run setup && webpack --mode production --progress --config config/webpack.config.js",
"client": "npm run setup && webpack-dev-server --host 0.0.0.0 --mode development --config config/webpack.config.js",
"coverage": "jest --coverage",
"coverage": "jest --coverage --testPathIgnorePatterns=/browser-test/",
"coveralls": "test -f ./coverage/lcov.info && cat ./coverage/lcov.info | coveralls || echo 'no coverage file found'",
"add-org": "plop --plopfile internals/generators/index.js",
"server": "npm run setup && nodemon server/start.js",
Expand All @@ -103,7 +104,8 @@
"lint:fix": "eslint '**/*.{js,jsx}' --fix",
"format": "prettier --write \"**/*.+(js|jsx|json|css|md)\"",
"format:check": "prettier -c \"**/*.+(js|jsx|json|css|md)\"",
"test": "jest",
"test": "jest --testPathIgnorePatterns=/browser-test/",
"browser-test": "jest browser-test --runInBand",
"test-inspect": "node inspect ./node_modules/.bin/jest --runInBand",
"stats": "STATS=true npx webpack-cli --profile --json --config config/webpack.config.js > compilation-stats.json && webpack-bundle-analyzer dist/stats.json"
},
Expand Down
Loading

0 comments on commit 4909e46

Please sign in to comment.