Add coupon call in frontend, add tests, fix api
This commit is contained in:
parent
f5ddff12e3
commit
82c1135f0e
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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.');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
mutation Coupon($input: CouponInput!){
|
||||||
|
coupon(input: $input) {
|
||||||
|
success
|
||||||
|
errors {
|
||||||
|
field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 = '';
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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('/')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue