Frontend testing (#3169)

This commit is contained in:
Patrick Quist
2022-02-04 18:35:04 +01:00
committed by GitHub
parent 2978b90ee5
commit 51047b6ad7
14 changed files with 1404 additions and 1 deletions

View File

@@ -5,6 +5,7 @@ etc
examples
out
views
cypress
# Autogenerated files
lib/asm-docs/generated/asm-docs-*.js

19
.github/workflows/test-frontend.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Compiler Explorer Frontend Testing
on: [push]
jobs:
cypress-run:
if: github.repository_owner == 'compiler-explorer'
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Clean
run: make clean
- name: Install prerequisites
run: make prereqs
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: npm run dev
wait-on: 'http://localhost:10240'

4
cypress.json Normal file
View File

@@ -0,0 +1,4 @@
{
"baseUrl": "http://127.0.0.1:10240/",
"downloadsFolder": "cypress/downloads"
}

View File

@@ -0,0 +1,15 @@
function runFrontendTest(name) {
it(name, () => {
cy.window().then((win) => {
return win.compilerExplorerFrontendTesting.run(name);
});
});
}
describe('Frontendtestresults', () => {
before(() => {
cy.visit('/');
});
runFrontendTest('HelloWorld');
});

View File

@@ -0,0 +1,28 @@
# Frontend testing
We have a mixture of typescript in the main website's code (located in `static/tests`) and Cypress (located in `cypress/integration`) to test and report on the workings of that code.
But there's always the possibility to use Cypress code to do UI checks and testing.
## Recommended
The recommended way of testing is to use typescript to test the inner workings of the various interfaces that are available.
This has the advantage of having types and being able to verify your code is consistent with the rest of the website and probably going to run correctly - without having to startup the website and Cypress.
## Adding a test
Steps to add a test:
* Create a new file in `static/tests` (copy paste from `static/tests/hello-world.ts`)
* Make sure to change the `description` as well as the test
* Add the file to the imports of `static/tests/_all.js`
* Add a `runFrontendTest()` call with the new test description to `cypress/integration/frontend-testing.js`
## Starting tests locally
You don't need to install an entire X server to actually run cypress (just xfvb).
You can find a complete list at https://docs.cypress.io/guides/getting-started/installing-cypress#System-requirements
If you have the prerequisites installed, you should be able to run `npx cypress run` - however, you will need to start the CE website seperately in another terminal before that.

1270
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -104,6 +104,7 @@
"codecov": "^3.8.3",
"css-loader": "^6.5.1",
"css-minimizer-webpack-plugin": "^3.3.1",
"cypress": "^9.2.0",
"deep-equal-in-any-order": "^1.1.15",
"eslint": "^8.5.0",
"eslint-config-prettier": "^8.3.0",

View File

@@ -22,6 +22,7 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
import { IFrontendTesting } from './tests/frontend-testing.interfaces';
import { Options } from './options.interfaces';
type CompilerExplorerOptions = Record<string, unknown> & Options
@@ -31,6 +32,7 @@ declare global {
httpRoot: string | null;
staticRoot: string | null;
compilerExplorerOptions: CompilerExplorerOptions;
compilerExplorerFrontendTesting: IFrontendTesting;
ga: any;
GoogleAnalyticsObject: any;
}

View File

@@ -52,6 +52,10 @@ var HistoryWidget = require('./history-widget').HistoryWidget;
var History = require('./history');
var presentation = require('./presentation');
if (!window.PRODUCTION) {
require('./tests/_all');
}
//css
require('bootstrap/dist/css/bootstrap.min.css');
require('golden-layout/src/css/goldenlayout-base.css');

2
static/tests/_all.js Normal file
View File

@@ -0,0 +1,2 @@
require('./frontend-testing');
require('./hello-world');

View File

@@ -0,0 +1,11 @@
export interface ITestable {
readonly description: string;
run(): Promise<void>;
}
export interface IFrontendTesting {
add(test: ITestable);
getAllTestNames(): string[];
run(testToRun: string): Promise<void>;
}

View File

@@ -0,0 +1,30 @@
import { IFrontendTesting, ITestable } from './frontend-testing.interfaces';
class FrontendTesting implements IFrontendTesting {
private testSuites: Array<ITestable> = [];
public add(test: ITestable) {
this.testSuites.push(test);
}
public getAllTestNames(): string[] {
return this.testSuites.map((val) => val.description);
}
private findTest(name: string) {
for (const suite of this.testSuites) {
if (suite.description === name) {
return suite;
}
}
throw new Error(`Can't find test ${name}`);
}
public async run(testToRun: string) {
const testSuite = this.findTest(testToRun);
await testSuite.run();
}
}
window.compilerExplorerFrontendTesting = new FrontendTesting();

View File

@@ -0,0 +1,13 @@
import { ITestable } from './frontend-testing.interfaces';
import { assert } from 'chai';
class HelloWorldTests implements ITestable {
public readonly description: string = 'HelloWorld';
public async run() {
const person = true;
assert.equal(person, true);
}
}
window.compilerExplorerFrontendTesting.add(new HelloWorldTests());

View File

@@ -30,7 +30,7 @@ import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import MonacoEditorWebpackPlugin from 'monaco-editor-webpack-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import {HotModuleReplacementPlugin, ProvidePlugin} from 'webpack';
import {DefinePlugin, HotModuleReplacementPlugin, ProvidePlugin} from 'webpack';
import {WebpackManifestPlugin} from 'webpack-manifest-plugin';
const __dirname = path.resolve(path.dirname(fileURLToPath(import.meta.url)));
@@ -61,6 +61,9 @@ const plugins = [
fileName: path.join(distPath, 'manifest.json'),
publicPath: '',
}),
new DefinePlugin({
'window.PRODUCTION': JSON.stringify(!isDev),
}),
];
if (isDev) {