Skip to content
Snippets Groups Projects
Commit f3d37205 authored by robinwilliam.hundt's avatar robinwilliam.hundt
Browse files

Getting frontend e2e tests working

parent 42802b09
No related branches found
No related tags found
No related merge requests found
Pipeline #85367 passed
...@@ -35,6 +35,7 @@ coverage_html/ ...@@ -35,6 +35,7 @@ coverage_html/
.vscode/ .vscode/
anon-export/ anon-export/
public/ public/
geckodriver.log
# node # node
node_modules node_modules
......
...@@ -2,6 +2,7 @@ stages: ...@@ -2,6 +2,7 @@ stages:
- build - build
- test - test
- build_image - build_image
- test_build
- pages - pages
- staging - staging
...@@ -25,6 +26,27 @@ build_test_env: ...@@ -25,6 +26,27 @@ build_test_env:
key: "$CI_JOB_NAME" key: "$CI_JOB_NAME"
paths: paths:
- .venv - .venv
tags:
- docker
build_frontend:
image: node:carbon
stage: build
script:
- cd frontend
- yarn
- yarn build
artifacts:
paths:
- frontend/dist
expire_in: 20 minutes
cache:
key: "$CI_JOB_NAME"
paths:
- frontend/dist
- frontend/node_modules/
tags:
- docker
# ============================== Testing section ============================= # # ============================== Testing section ============================= #
# ----------------------------- Backend subsection --------------------------- # # ----------------------------- Backend subsection --------------------------- #
...@@ -34,6 +56,8 @@ build_test_env: ...@@ -34,6 +56,8 @@ build_test_env:
- source .venv/bin/activate - source .venv/bin/activate
dependencies: dependencies:
- build_test_env - build_test_env
tags:
- docker
test_pytest: test_pytest:
<<: *test_definition_virtualenv <<: *test_definition_virtualenv
...@@ -58,32 +82,43 @@ test_flake8: ...@@ -58,32 +82,43 @@ test_flake8:
# ----------------------------- Frontend subsection -------------------------- # # ----------------------------- Frontend subsection -------------------------- #
.test_template_frontend: &test_definition_frontend .test_template_frontend: &test_definition_frontend
image: crbanman/nightwatch image: docker.gitlab.gwdg.de/robinwilliam.hundt/python-geckodriver:master
when: manual
before_script: before_script:
- cd frontend/ - source .venv/bin/activate
dependencies:
- build_test_env
- build_frontend
tags:
- docker
test_frontend: test_frontend:
<<: *test_definition_frontend <<: *test_definition_frontend
# when: manual
stage: test stage: test
services:
- postgres:9.6
script: script:
- yarn install - cp frontend/dist/index.html core/templates
- yarn test:e2e - python util/format_index.py
cache: - python manage.py collectstatic --no-input
key: "$CI_JOB_NAME" - HEADLESS_TESTS=True pytest --ds=grady.settings.test functional_tests
paths:
- frontend/node_modules/
# =========================== Build Image section ============================ # # =========================== Build Image section ============================ #
build_backend: build_backend:
image: docker:latest image: docker:latest
stage: build_image stage: build_image
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
script: script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $IMAGE_TAG . - docker build -t $IMAGE_TAG .
- docker tag $IMAGE_TAG $IMAGE_TAG-$CI_COMMIT_SHA - docker tag $IMAGE_TAG $IMAGE_TAG-$CI_COMMIT_SHA
- docker push $IMAGE_TAG - docker push $IMAGE_TAG
tags:
- docker
# =========================== Gitlab pages section =========================== # # =========================== Gitlab pages section =========================== #
pages: pages:
...@@ -101,6 +136,7 @@ pages: ...@@ -101,6 +136,7 @@ pages:
only: only:
- master - master
# ============================== Staging section ============================= # # ============================== Staging section ============================= #
.staging_template: &staging_definition .staging_template: &staging_definition
stage: staging stage: staging
...@@ -109,6 +145,8 @@ pages: ...@@ -109,6 +145,8 @@ pages:
- master - master
before_script: before_script:
- apk add --update py-pip && pip install docker-compose - apk add --update py-pip && pip install docker-compose
tags:
- grady-staging
staging: staging:
<<: *staging_definition <<: *staging_definition
......
...@@ -31,7 +31,9 @@ class TutorSerializer(DynamicFieldsModelSerializer): ...@@ -31,7 +31,9 @@ class TutorSerializer(DynamicFieldsModelSerializer):
return t.feedback_validated if hasattr(t, 'feedback_validated') else 0 return t.feedback_validated if hasattr(t, 'feedback_validated') else 0
def create(self, validated_data) -> models.UserAccount: def create(self, validated_data) -> models.UserAccount:
log.info("Crating tutor from data %s", validated_data) log_validated_data = dict(validated_data)
log_validated_data['password'] = '******'
log.info("Crating tutor from data %s", log_validated_data)
return user_factory.make_tutor( return user_factory.make_tutor(
username=validated_data['username'], username=validated_data['username'],
password=validated_data.get('password'), password=validated_data.get('password'),
......
...@@ -15,7 +15,7 @@ import { ...@@ -15,7 +15,7 @@ import {
function getInstanceBaseUrl (): string { function getInstanceBaseUrl (): string {
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
return `https://${window.location.host}${window.location.pathname}`.replace(/\/+$/, '') return `${window.location.protocol}//${window.location.host}${window.location.pathname}`.replace(/\/+$/, '')
} else { } else {
return 'http://localhost:8000/' return 'http://localhost:8000/'
} }
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
Datenschutzerklärung Datenschutzerklärung
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
<GDPRNotice/> <GDPRNotice id="gdpr-notice"/>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-btn @click="acceptedGDPR = true">Einwilligen</v-btn> <v-btn @click="acceptedGDPR = true" id="accept-gdpr-notice">Einwilligen</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
<v-card v-else> <v-card v-else>
...@@ -20,16 +20,18 @@ ...@@ -20,16 +20,18 @@
required required
autofocus autofocus
v-model="credentials.username" v-model="credentials.username"
id="input-register-username"
/> />
<v-text-field <v-text-field
label="Password" label="Password"
required required
type="password" type="password"
v-model="credentials.password" v-model="credentials.password"
id="input-register-password"
/> />
</v-card-text> </v-card-text>
<v-card-actions class="justify-center"> <v-card-actions class="justify-center">
<v-btn flat :loading="loading" @click="register">submit</v-btn> <v-btn flat :loading="loading" @click="register" id="register-submit">submit</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</template> </template>
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
type="password" type="password"
required required
/> />
<v-btn @click="registerDialog = true">register</v-btn> <v-btn @click="registerDialog = true" id="register">register</v-btn>
<v-btn :loading="loading" type="submit" color="primary">Access</v-btn> <v-btn :loading="loading" type="submit" color="primary">Access</v-btn>
</v-form> </v-form>
</v-flex> </v-flex>
......
import os
import time
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.options import Options
from core.models import UserAccount
from functional_tests.util import get_frontend_url
from util.factories import make_test_data
LiveServerTestCase.port = int(os.environ.get('LIVE_SERVER_PORT', 0))
class LoginPageTest(LiveServerTestCase):
def setUp(self):
self.live_server_url = get_frontend_url(self.live_server_url)
options = Options()
# funnily the method is marked deprecated but the alternative setter is not working...
options.headless = bool(os.environ.get('HEADLESS_TESTS', False))
self.browser = webdriver.Firefox(options=options)
self.browser.implicitly_wait(5)
self.test_data = make_test_data(data_dict={
'submission_types': [
{
'name': '01. Sort this or that',
'full_score': 35,
'description': 'Very complicated',
'solution': 'Trivial!'
},
{
'name': '02. Merge this or that or maybe even this',
'full_score': 35,
'description': 'Very complicated',
'solution': 'Trivial!'
}
],
'students': [
{'username': 'student01', 'password': 'p'},
{'username': 'student02', 'password': 'p'}
],
'tutors': [
{'username': 'tutor01', 'password': 'p'},
{'username': 'tutor02', 'password': 'p'}
],
'reviewers': [
{'username': 'reviewer', 'password': 'p'}
],
'submissions': [
{
'text': 'function blabl\n'
' on multi lines\n'
' for blabla in bla:\n'
' lorem ipsum und so\n',
'type': '01. Sort this or that',
'user': 'student01',
'feedback': {
'score': 5,
'is_final': True,
'feedback_lines': {
'1': [{
'text': 'This is very bad!',
'of_tutor': 'tutor01'
}],
}
}
},
{
'text': 'function blabl\n'
' asasxasx\n'
' lorem ipsum und so\n',
'type': '02. Merge this or that or maybe even this',
'user': 'student01'
},
{
'text': 'function blabl\n'
' on multi lines\n'
' asasxasx\n'
' lorem ipsum und so\n',
'type': '01. Sort this or that',
'user': 'student02'
},
{
'text': 'function lorem ipsum etc\n',
'type': '02. Merge this or that or maybe even this',
'user': 'student02'
},
]}
)
def tearDown(self):
self.browser.quit()
def _login(self, account):
self.browser.get(self.live_server_url)
username_input = self.browser.find_element_by_xpath('//input[@aria-label="Username"]')
username_input.send_keys(account.username)
password_input = self.browser.find_element_by_xpath('//input[@aria-label="Password"]')
password_input.send_keys('p')
self.browser.find_element_by_xpath('//button[@type="submit"]').send_keys(Keys.ENTER)
time.sleep(1)
def test_tutor_can_login(self):
tutor = self.test_data['tutors'][0]
self._login(tutor)
self.assertTrue(self.browser.current_url.endswith('#/home'))
def test_reviewer_can_login(self):
reviewer = self.test_data['reviewers'][0]
self._login(reviewer)
self.assertTrue(self.browser.current_url.endswith('#/home'))
def test_student_can_login(self):
student = self.test_data['students'][0]
self._login(student)
self.assertTrue(self.browser.current_url.endswith('#/home'))
def test_can_register_account(self):
username = 'danny'
password = 'redrum-is-murder-reversed'
self.browser.get(self.live_server_url)
self.browser.find_element_by_id('register').click()
self.browser.find_element_by_id('gdpr-notice')
self.browser.find_element_by_id('accept-gdpr-notice').click()
username_input = self.browser.find_element_by_id('input-register-username')
username_input.send_keys(username)
password_input = self.browser.find_element_by_id('input-register-password')
password_input.send_keys(password)
self.browser.find_element_by_id('register-submit').click()
time.sleep(1)
tutor = UserAccount.objects.get(username=username)
self.assertEqual(UserAccount.TUTOR, tutor.role)
self.assertFalse(tutor.is_active, "Tutors should be inactive after registered")
import os
def get_frontend_url(live_server_url):
return os.environ.get('FRONTEND_URL', live_server_url)
...@@ -127,6 +127,7 @@ AUTH_USER_MODEL = 'core.UserAccount' ...@@ -127,6 +127,7 @@ AUTH_USER_MODEL = 'core.UserAccount'
AUTH_PASSWORD_VALIDATORS = [] AUTH_PASSWORD_VALIDATORS = []
CORS_ORIGIN_WHITELIST = ( CORS_ORIGIN_WHITELIST = (
'localhost:8080' 'localhost:8080'
'localhost:8000'
) )
REST_FRAMEWORK = { REST_FRAMEWORK = {
......
...@@ -2,3 +2,4 @@ flake8~=3.5.0 ...@@ -2,3 +2,4 @@ flake8~=3.5.0
pre-commit~=1.4.1 pre-commit~=1.4.1
pytest-cov~=2.5.1 pytest-cov~=2.5.1
pytest-django~=3.1.2 pytest-django~=3.1.2
selenium~=3.14.1
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment