Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
andyjmaclean committed Apr 6, 2023
2 parents c9a5f18 + 6af682b commit 32dec29
Show file tree
Hide file tree
Showing 100 changed files with 6,528 additions and 9,444 deletions.
8 changes: 6 additions & 2 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ module.exports = {
env: {
node: true
},
ignorePatterns: ['**/dist/*', '**/cypress/plugins/*', '**/cypress/fixtures/*'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: path.resolve(__dirname, './tsconfig.json'),
noWatch: true,
sourceType: 'module',
tsconfigRootDir: __dirname
},
plugins: ['@typescript-eslint', '@typescript-eslint/tslint', 'rxjs'],
extends: ['plugin:@typescript-eslint/eslint-recommended'],
plugins: ['@typescript-eslint', 'rxjs'],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
rules: {
'rxjs/no-async-subscribe': 'error',
'rxjs/no-ignored-observable': 'error',
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.angular/cache
# See http://help.github.com/ignore-files/ for more about ignoring files.
npm-debug.log
.DS_Store
Expand Down
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM nginx:1.18.0-alpine
CMD ["nginx", "-g", "daemon off;"]
COPY ./dist /usr/share/nginx/html
COPY ./env.copy.sh .
RUN chmod 755 ./env.copy.sh
ENTRYPOINT ["sh", "./env.copy.sh"]
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A visualisation utility for Europeana API data.

## Getting started

Make sure you have `node` version 12 and `npm` version 6.x:
Make sure you have `node` version 14.7.8 and `npm` version 6.x:

node --version
npm --version
Expand All @@ -15,6 +15,14 @@ Get the `npm` dependencies:

npm install

## Development environment

To facilitate containerisation the standard angular way of setting environment variables has been amended.

The standard `environment.ts` file exists under `src/app/environments/` but its contents define a function that can load variables from an external source, in this case `src/assets/env.js`.

The file `src/assets/env.js` should therefore be modified before starting the development server.

## Development server

Run `npm run start` for a dev server. Navigate to [http://localhost:4200/](http://localhost:4200/). The app will automatically reload if you change any of the source files.
Expand Down Expand Up @@ -72,3 +80,46 @@ We use jenkins to deploy. Make sure you can access [https://jenkins.eanadev.org/

- `statistics-dashboard-test`
- `statistics-dashboard-acceptance`

## Docker

To make a (parameterised) docker image of the app first run this command:

`npm run dist-localised`

and then copy the output of that command (from the dist directory) into a docker nginx image:

`docker build -t statistics-dashboard-app-image:version .`

The image runtime configuration is only set on container startup, so environment variables have to be passed when it's run. Here they are passed using the (local) project `env_file`:

`docker run -it --rm -d -p 8080:8080 --env-file=deployment/local/env_file --name stats-dash statistics-dashboard-app-image:version`

As with the `src/assets/env.js` file for the development server, the `env_file` file should be adjusted before the nginx server is started.

Note: by default the docker image's nginx is configured to redirect the browser to the `https` protocol. To run the image locally or in environments that haven't been configured for `https` the image can be run with the `nginx.conf` file mapped to a non-https variant by using the `-v` (volume) option, i.e.:

`docker run -it --rm -d -p 8080:8080 --env-file=deployment/local/env_file -v deployment/local/nginx.conf:/etc/nginx/nginx.conf --name stats-dash statistics-dashboard-app-image:version`

## Kubernetes

Running the script:

`./deployment/k8s-deploy.sh -i myDockerImage`

will deploy the app to a local Kubernetes cluster.

The script accepts the parameter flags:
- -c (context) the kubernetes context
- -d (delete) flag that the app should be deleted
- -h (help) shows a help message
- -i (image) the application image to deploy
- -r (replicas) hyphen-separated integers defining the min / max number of replicas
- -t (target) the deploy target: local, test, acceptance, production
- -u (utilisation) the CPU usage threshold for autoscaling

so the command:

`./deployment/k8s-deploy.sh -d -t acceptance -i myDockerImage`

...will delete myDockerImage in the default context with the acceptance namespace.
15 changes: 2 additions & 13 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"allowedCommonJsDependencies": [
"rgbcolor",
"core-js",
"polylabel",
"raf",
Expand Down Expand Up @@ -131,17 +132,6 @@
"codeCoverageExclude": ["src/app/_mocked/*.ts"]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
Expand All @@ -156,6 +146,5 @@
}
}
}
},
"defaultProject": "statistics-dashboard"
}
}
20 changes: 20 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { defineConfig } from 'cypress'

export default defineConfig({
blockHosts: ['*fonts.googleapis.com', '*fonts.gstatic.com'],
screenshotsFolder: 'tmp/cypress-screenshots/',
video: false,
videosFolder: 'tmp/cypress-videos/',
viewportHeight: 768,
viewportWidth: 1024,
env: {
dataServer: 'http://127.0.0.1:3001',
},
e2e: {
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:4280',
excludeSpecPattern: ['tsconfig.json'],
},
})
13 changes: 0 additions & 13 deletions cypress.json

This file was deleted.

File renamed without changes.
208 changes: 208 additions & 0 deletions cypress/e2e/app.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
context('Statistics Dashboard', () => {

const force = {force: true};
const host = 'http://localhost:4280';
const urlContentTier = '/data/contentTier';
const urlParamCTZero = 'content-tier-zero=';
const urlParamCTZeroTrue = `?${urlParamCTZero}true`;

describe('App General', () => {
it('should show the feedback link (landing page / data page)', () => {
cy.visit('/');
cy.get('[data-e2e=user-assistance]').should('have.length', 1);
cy.visit(urlContentTier);
cy.get('[data-e2e=user-assistance]').should('have.length', 1);
});
});

describe('App Route History', () => {

it('should keep filter controls synced with the url history', () => {
const baseUrl = `${host}${urlContentTier}`;
const selFilter = `.filters-header + .filters .filter`;
const selFilterOpener = '.filter-opener';
const selFilterValueLabel = `${selFilter} .checkbox-label`;
const selFilterRemove = '.rm-filter .checkbox-label';

cy.visit(urlContentTier);
cy.location('href').should('equal', baseUrl);
cy.get(selFilterRemove).should('not.exist');

// filter on country Belgium / confirm url & filter rm buttons updated

cy.get(selFilterOpener).eq(1).click(force);
cy.get(selFilterValueLabel).contains('Belgium').click(force);

cy.location('href').should('equal', `${baseUrl}?country=Belgium`);
cy.get(selFilterRemove).contains('Belgium').should('have.length', 1);

// filter on Metadata Tier 0 / confirm url & filter rm buttons updated

cy.get(selFilterRemove).contains('Tier 0').should('not.exist');
cy.get(selFilterOpener).eq(0).click(force);
cy.get(selFilterValueLabel).contains('Tier 0').click(force);

cy.location('href').should('equal', `${baseUrl}?metadataTier=0&country=Belgium`);
cy.get(selFilterRemove).contains('Tier 0').should('have.length', 1);

// filter on type IMAGE / confirm url & filter rm buttons updated

cy.get(selFilterRemove).contains('IMAGE').should('not.exist');
cy.get(selFilterOpener).eq(5).click(force);
cy.get(selFilterValueLabel).contains('IMAGE').click(force);

cy.location('href').should('equal', `${baseUrl}?metadataTier=0&country=Belgium&type=IMAGE`);
cy.get(selFilterRemove).contains('IMAGE').should('have.length', 1);


// filter on inexistent dataset id / confirm url & filter rm buttons updated

const selDatasetId = '.dataset-name';

cy.get(selFilterRemove).contains('dataset_not_found').should('not.exist');
cy.get(selDatasetId).type('dataset_not_found{enter}', force);
cy.get(selFilterRemove).contains('dataset_not_found').should('have.length', 1);

// History Checks

// go back (remove dataset id)

cy.go('back');

cy.get(selFilterRemove).contains('dataset_not_found').should('not.exist');
cy.get(selFilterRemove).contains('IMAGE').should('exist');
cy.get(selFilterRemove).contains('Tier 0').should('exist');
cy.get(selFilterRemove).contains('Belgium').should('exist');


// go back (remove image)

cy.go('back');

cy.get(selFilterRemove).contains('IMAGE').should('not.exist');
cy.get(selFilterRemove).contains('Tier 0').should('exist');
cy.get(selFilterRemove).contains('Belgium').should('exist');
cy.location('href').should('equal', `${baseUrl}?metadataTier=0&country=Belgium`);

// go back (remove Tier 0)
cy.go('back');

cy.get(selFilterRemove).contains('Tier 0').should('not.exist');
cy.get(selFilterRemove).contains('Belgium').should('exist');
cy.location('href').should('equal', `${baseUrl}?country=Belgium`);

// go back (remove Country)
cy.go('back');

cy.get(selFilterRemove).should('not.exist');
cy.location('href').should('equal', baseUrl);

// go forward (re-add Country)
cy.go('forward');

cy.get(selFilterRemove).contains('Belgium').should('exist');
cy.get(selFilterRemove).contains('IMAGE').should('not.exist');
cy.location('href').should('equal', `${baseUrl}?country=Belgium`);

// go forward (re-add Tier 0)

cy.go('forward');

cy.get(selFilterRemove).contains('Belgium').should('exist');
cy.get(selFilterRemove).contains('Tier 0').should('exist');
cy.get(selFilterRemove).contains('IMAGE').should('not.exist');
cy.location('href').should('equal', `${baseUrl}?metadataTier=0&country=Belgium`);

// go forward (re-add IMAGE)
cy.go('forward');

cy.get(selFilterRemove).contains('Belgium').should('exist');
cy.get(selFilterRemove).contains('Tier 0').should('exist');
cy.get(selFilterRemove).contains('IMAGE').should('exist');
cy.location('href').should('equal', `${baseUrl}?metadataTier=0&country=Belgium&type=IMAGE`);
});
});

describe('App Content Tier Zero', () => {
const selCTZero = '#ctZero';
const selLinkDataContentTier = '[data-e2e=link-entry-ct]';
const selLinkHeader = '[data-e2e=link-home-header]';

const checkCTZeroChangesUrl = (): void => {
cy.get(selCTZero).should('have.length', 1);
cy.get(selCTZero).should('not.be.checked');
cy.url().should('not.contain', urlParamCTZero);

cy.get(selCTZero).click(force);
cy.get(selCTZero).should('be.checked');
cy.url().should('contain', urlParamCTZero);
};

it('the url should reflect content-tier-zero visibility (landing page)', () => {
cy.visit('/');
checkCTZeroChangesUrl();
});

it('the url should reflect content-tier-zero visibility (data page)', () => {
cy.visit(urlContentTier);
checkCTZeroChangesUrl();
});

it('the content-tier-zero should be remembered between pages (click test)', () => {
cy.visit('/');
cy.get(selCTZero).click(force);
cy.get(selCTZero).should('be.checked');
cy.url().should('contain', urlParamCTZero);

const goBackAndForth = () => {
cy.url().should('not.contain', '/data');
cy.get(selLinkDataContentTier).click(force);

cy.get(selCTZero).should('be.checked');
cy.url().should('contain', urlParamCTZero);

cy.get(selLinkHeader).click(force);

cy.get(selCTZero).should('be.checked');
cy.url().should('contain', urlParamCTZero);
};
goBackAndForth();
goBackAndForth();
});

it('the content-tier-zero should be remembered between pages (history test)', () => {

cy.visit('/')
const expectedHistory = ['/', `/${urlParamCTZeroTrue}`, `${urlContentTier}${urlParamCTZeroTrue}`, `${urlContentTier}`, '/'];

cy.location('search').should('equal', '');
cy.location('pathname').should('equal', '/');
cy.location('href').should('equal', `${host}${expectedHistory[0]}`);

cy.get(selCTZero).click(force);
cy.location('href').should('equal', `${host}${expectedHistory[1]}`);

cy.get(selLinkDataContentTier).click(force);
cy.location('href').should('equal', `${host}${expectedHistory[2]}`);

cy.get(selCTZero).click(force);
cy.location('href').should('equal', `${host}${expectedHistory[3]}`);

cy.get(selLinkHeader).click(force);
cy.location('href').should('equal', `${host}${expectedHistory[4]}`);

// browser back
for(let i = 0; i < expectedHistory.length -1; i++) {
const historyIndex = expectedHistory.length - (i + 1);
cy.location('href').should('equal', `${host}${expectedHistory[historyIndex]}`);
cy.go('back');
}

// browser forward
for(let i = 0; i < expectedHistory.length -1; i++) {
cy.location('href').should('equal', `${host}${expectedHistory[i]}`);
cy.go('forward');
}
});
});
});
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 32dec29

Please sign in to comment.