Add coupon call in frontend, add tests, fix api

This commit is contained in:
Christian Cueni 2020-02-13 10:01:45 +01:00
parent f5ddff12e3
commit 82c1135f0e
14 changed files with 17329 additions and 17021 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
const schema = require('../fixtures/schema.json');
describe('Email Verifcation', () => {
beforeEach(() => {
cy.server();
});
it('forwards to homepage if confirmation key is correct', () => {
cy.viewport('macbook-15');
cy.mockGraphql({
schema: schema,
operations: {
Coupon: variables => {
return {
coupon: {
errors: [],
success: true
}
}
},
}
});
cy.login('rahel.cueni', 'test', true)
cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen');
cy.visit('/license-activation');
cy.redeemCoupon('12345asfd');
cy.get('finishTest')
});
it('displays error if input is missing', () => {
cy.viewport('macbook-15');
cy.login('rahel.cueni', 'test', true)
cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen');
cy.visit('/license-activation');
cy.redeemCoupon('');
cy.get('[data-cy="coupon-local-errors"]').contains('Coupon ist ein Pflichtfeld.');
});
it('displays error if coupon input is wrong', () => {
cy.viewport('macbook-15');
cy.mockGraphql({
schema: schema,
operations: {
Coupon: variables => {
return {
coupon: {
errors: [{
field: 'invalid_coupon'
}],
success: false
}
}
},
}
});
cy.login('rahel.cueni', 'test', true)
cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen');
cy.visit('/license-activation');
cy.redeemCoupon('12345asfd');
cy.get('[data-cy="coupon-remote-errors"]').contains('Der angegebene Coupon-Code ist falsch.');
});
it('displays error if an error occures', () => {
cy.viewport('macbook-15');
cy.mockGraphql({
schema: schema,
operations: {
Coupon: variables => {
return {
coupon: {
errors: [{
field: 'unknown_error'
}],
success: false
}
}
},
}
});
cy.login('rahel.cueni', 'test', true)
cy.get('[data-cy="rooms-link"]').contains('Alle Räume anzeigen');
cy.visit('/license-activation');
cy.redeemCoupon('12345asfd');
cy.get('[data-cy="coupon-remote-errors"]').contains('Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.');
});
});

View File

@ -20,7 +20,7 @@ describe('Login', () => {
it('displays error message if password is wrong', () => { it('displays error message if password is wrong', () => {
cy.viewport('macbook-15'); cy.viewport('macbook-15');
cy.route('POST', isEmailAvailableUrl, "false"); cy.route('POST', isEmailAvailableUrl, 'false');
cy.route({ cy.route({
method: 'POST', method: 'POST',
status: 401, status: 401,

View File

@ -54,7 +54,7 @@ Cypress.Commands.add('apolloLogin', (username, password) => {
// todo: replace with apollo call // todo: replace with apollo call
Cypress.Commands.add("login", (username, password, visitLogin = false) => { Cypress.Commands.add("login", (username, password, visitLogin = false) => {
if (visitLogin) { if (visitLogin) {
cy.visit('/login'); cy.visit('/login-local');
} }
if (username != '') { if (username != '') {
@ -159,3 +159,10 @@ Cypress.Commands.add('register', (prefix, firstname, lastname, password, passwor
cy.get('[data-cy="register-button"]').click(); cy.get('[data-cy="register-button"]').click();
}); });
Cypress.Commands.add('redeemCoupon', coupon => {
if (coupon !== '') {
cy.get('[data-cy="coupon-input"]').type(coupon);
}
cy.get('[data-cy="coupon-button"]').click();
})

View File

@ -0,0 +1,8 @@
mutation Coupon($input: CouponInput!){
coupon(input: $input) {
success
errors {
field
}
}
}

View File

@ -12,7 +12,7 @@
id="coupon" id="coupon"
name="coupon" name="coupon"
type="coupon" type="coupon"
data-vv-as="Passwort" data-vv-as="Coupon"
v-model="coupon" v-model="coupon"
v-validate="'required'" v-validate="'required'"
:class="{ 'skillboxform-input__input--error': errors.has('coupon') }" :class="{ 'skillboxform-input__input--error': errors.has('coupon') }"
@ -33,9 +33,6 @@
data-cy="coupon-remote-errors" data-cy="coupon-remote-errors"
>{{ error }}</small> >{{ error }}</small>
</div> </div>
<div class="skillboxform-input">
<small class="skillboxform-input__error" data-cy="coupon-error" v-if="loginError">{{couponError}}</small>
</div>
<div class="actions"> <div class="actions">
<button class="button button--primary button--big actions__submit" data-cy="coupon-button">Coupon abschicken</button> <button class="button button--primary button--big actions__submit" data-cy="coupon-button">Coupon abschicken</button>
</div> </div>
@ -53,29 +50,44 @@
<script> <script>
import REDEEM_COUPON from '@/graphql/gql/mutations/redeemCoupon.gql';
import ME_QUERY from '@/graphql/gql/meQuery.gql'; import ME_QUERY from '@/graphql/gql/meQuery.gql';
// import {login} from '../hep-client/index';
export default { export default {
components: {}, components: {},
methods: { methods: {
validateBeforeSubmit() { validateBeforeSubmit() {
// this.$validator.validate().then(result => { this.$validator.validate().then(result => {
// this.submitted = true; this.submitted = true;
// let that = this; let that = this;
// if (result) { if (result) {
this.$apollo.mutate({
// login(this.password) mutation: REDEEM_COUPON,
// .then((response) => { variables: {
// console.log(response) input: {
// }) couponCodeInput: this.coupon
// .catch((error) => { }
// console.log(error) },
// this.registrationError = 'Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals.'; update(
// }); store,
// } {
// }); data: {coupon}
}
) {
if (coupon.success) {
console.log('handle happy path');
} else {
if (coupon.errors[0].field === 'invalid_coupon') {
that.couponErrors = ['Der angegebene Coupon-Code ist falsch.'];
} else {
that.couponErrors = ['Es ist ein Fehler aufgetreten. Bitte versuchen Sie es nochmals oder kontaktieren Sie den Administrator.'];
}
}
}
});
}
});
}, },
resetForm() { resetForm() {
this.coupon = ''; this.coupon = '';

View File

@ -20,6 +20,7 @@
class="start-sections__section" class="start-sections__section"
title="Räume" title="Räume"
subtitle="Beiträge mit der Klasse teilen" subtitle="Beiträge mit der Klasse teilen"
data-cy="rooms-link"
link-text="Alle Räume anzeigen" link-text="Alle Räume anzeigen"
route="/rooms" route="/rooms"
> >

View File

@ -10,6 +10,7 @@ from assignments.schema.queries import AssignmentsQuery, StudentSubmissionQuery
from basicknowledge.queries import BasicKnowledgeQuery from basicknowledge.queries import BasicKnowledgeQuery
from books.schema.mutations.main import BookMutations from books.schema.mutations.main import BookMutations
from books.schema.queries import BookQuery from books.schema.queries import BookQuery
from core.schema.mutations.coupon import CouponMutations
from core.schema.mutations.main import CoreMutations from core.schema.mutations.main import CoreMutations
from notes.mutations import NoteMutations from notes.mutations import NoteMutations
from objectives.mutations import ObjectiveMutations from objectives.mutations import ObjectiveMutations
@ -36,7 +37,7 @@ class Query(UsersQuery, AllUsersQuery, ModuleRoomsQuery, RoomsQuery, ObjectivesQ
class Mutation(BookMutations, RoomMutations, AssignmentMutations, ObjectiveMutations, CoreMutations, PortfolioMutations, class Mutation(BookMutations, RoomMutations, AssignmentMutations, ObjectiveMutations, CoreMutations, PortfolioMutations,
ProfileMutations, SurveyMutations, NoteMutations, RegistrationMutations, SpellCheckMutations, ProfileMutations, SurveyMutations, NoteMutations, RegistrationMutations, SpellCheckMutations,
graphene.ObjectType): CouponMutations, graphene.ObjectType):
if settings.DEBUG: if settings.DEBUG:
debug = graphene.Field(DjangoDebug, name='_debug') debug = graphene.Field(DjangoDebug, name='_debug')

View File

@ -138,10 +138,13 @@ class HepClient:
try: try:
response = self._call('/rest/deutsch/V1/coupon/{}/customer/{}'.format(coupon, customer_id), method='put') response = self._call('/rest/deutsch/V1/coupon/{}/customer/{}'.format(coupon, customer_id), method='put')
except HepClientException as e: except HepClientException as e:
if e.args[0] == 201: return None
return None
return response response_data = response.json()
if response_data[0] == '201':
return None
return response_data[0]
def myskillbox_product_for_customer(self, admin_token, customer_id): def myskillbox_product_for_customer(self, admin_token, customer_id):
orders = self._customer_orders(admin_token, customer_id) orders = self._customer_orders(admin_token, customer_id)

View File

@ -38,10 +38,10 @@ class Coupon(relay.ClientIDMutation):
try: try:
response = hep_client.coupon_redeem(coupon_code, hep_id) response = hep_client.coupon_redeem(coupon_code, hep_id)
except HepClientException: except HepClientException:
return cls(success=False, errors=[{'field': 'unkown_error'}]) return cls(success=False, errors=[{'field': 'unknown_error'}])
if not response: if not response:
return cls(success=False, errors=[{'field': 'invalid_code'}]) return cls(success=False, errors=[{'field': 'invalid_coupon'}])
license, error_msg = check_and_create_licenses(hep_client, info.context.user) license, error_msg = check_and_create_licenses(hep_client, info.context.user)
@ -52,3 +52,7 @@ class Coupon(relay.ClientIDMutation):
create_role_for_user(info.context.user, license.for_role.key) create_role_for_user(info.context.user, license.for_role.key)
return cls(success=True, errors=[]) return cls(success=True, errors=[])
class CouponMutations:
redeem_coupon = Coupon.Field()

View File

@ -373,8 +373,8 @@ USE_LOCAL_REGISTRATION = True
# HEP # HEP
HEP_ADMIN_USER = "adminuser" HEP_ADMIN_USER = "myskillbox"
HEP_ADMIN_PASSWORD = "password" HEP_ADMIN_PASSWORD = "dSgqCv7zhEMmSNrw"
HEP_URL = 'https://stage.hep-verlag.ch' HEP_URL = 'https://stage.hep-verlag.ch'

View File

@ -15,11 +15,12 @@ from datetime import datetime, timedelta
class MockResponse: class MockResponse:
def __init__(self, status_code): def __init__(self, status_code, data={}):
self.status_code = status_code self.status_code = status_code
self.data = data
def json(self): def json(self):
return {} return self.data
## Setup json data ## Setup json data

View File

@ -56,7 +56,7 @@ class CouponTests(TestCase):
} }
}) })
@patch.object(requests, 'put', return_value=MockResponse(200)) @patch.object(requests, 'put', return_value=MockResponse(200, data=['200', 'Coupon successfully redeemed']))
@patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS) @patch.object(HepClient, '_customer_orders', return_value=VALID_TEACHERS_ORDERS)
@patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'}) @patch.object(HepClient, 'fetch_admin_token', return_value={'token': 'AABBCCDDEE**44566'})
def test_user_has_valid_coupon(self, admin_mock, orders_mock, response_mock): def test_user_has_valid_coupon(self, admin_mock, orders_mock, response_mock):
@ -73,14 +73,14 @@ class CouponTests(TestCase):
self.assertTrue(result.get('data').get('coupon').get('success')) self.assertTrue(result.get('data').get('coupon').get('success'))
self.assertTrue(self.user.is_authenticated) self.assertTrue(self.user.is_authenticated)
@patch.object(requests, 'put', return_value=MockResponse(201)) @patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon']))
def test_user_has_invalid_coupon(self, response_mock): def test_user_has_invalid_coupon(self, response_mock):
result = self.make_coupon_mutation('COUPON--1234', self.client) result = self.make_coupon_mutation('COUPON--1234', self.client)
self.assertFalse(result.get('data').get('coupon').get('success')) self.assertFalse(result.get('data').get('coupon').get('success'))
self.assertEqual(result.get('data').get('coupon').get('errors')[0].get('field'), 'invalid_code') self.assertEqual(result.get('data').get('coupon').get('errors')[0].get('field'), 'invalid_coupon')
@patch.object(requests, 'put', return_value=MockResponse(201)) @patch.object(requests, 'put', return_value=MockResponse(200, data=['201', 'Invalid Coupon']))
def test_unauthenticated_user_cannot_redeem(self, response_mock): def test_unauthenticated_user_cannot_redeem(self, response_mock):
request = RequestFactory().post('/') request = RequestFactory().post('/')