Commit 4fe65605 authored by Konstantin Schulz's avatar Konstantin Schulz

code coverage from unit tests is now at 100%

parent 31ffd1b7
Pipeline #11047 failed with stage
in 3 minutes and 18 seconds
......@@ -4,7 +4,7 @@ coverage:
stage: test
script:
- docker-compose build
- docker-compose run --rm --entrypoint="npm run test" mc_frontend
- docker-compose run --rm --entrypoint="npm run test-ci" mc_frontend
coverage: '/Statements.*?(\d+(?:\.\d+)?)%/'
tags:
- node
......
import { AppPage } from './app.po';
describe('new App', () => {
describe('Machina Callida', () => {
let page: AppPage;
beforeEach(() => {
......@@ -9,6 +9,6 @@ describe('new App', () => {
it('should be blank', () => {
page.navigateTo();
expect(page.getParagraphText()).toContain('The world is your oyster.');
expect(page.getParagraphText()).toContain('Home');
});
});
{
"name": "mc_frontend",
"version": "1.7.8",
"version": "1.8.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
{
"name": "mc_frontend",
"version": "1.7.9",
"version": "1.8.0",
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
"ng": "ng",
"start": "ng serve --port 8100",
"build": "ng build",
"test": "ng test --code-coverage --watch=false",
"test-debug": "ng test --watch=true --browsers=Chrome",
"test-ci": "ng test --code-coverage --watch=false",
"test-cov": "ng test --code-coverage --watch=true",
"test-debug": "ng test --watch=true --browsers=Chrome",
"lint": "ng lint",
"e2e": "ng e2e"
},
......
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
export const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'confirm-cancel', loadChildren: './confirm-cancel/confirm-cancel.module#ConfirmCancelPageModule' },
{ path: 'author', loadChildren: './author/author.module#AuthorPageModule' },
......@@ -18,15 +18,16 @@ const routes: Routes = [
{ path: 'test', loadChildren: './test/test.module#TestPageModule' },
{ path: 'text-range', loadChildren: './text-range/text-range.module#TextRangePageModule' },
{ path: 'vocabulary-check', loadChildren: './vocabulary-check/vocabulary-check.module#VocabularyCheckPageModule' },
{ path: 'exercise', loadChildren: './exercise/exercise.module#ExercisePageModule' }, { path: 'exercise-list', loadChildren: './exercise-list/exercise-list.module#ExerciseListPageModule' },
{ path: 'doc-voc-unit', loadChildren: './doc-voc-unit/doc-voc-unit.module#DocVocUnitPageModule' },
{ path: 'doc-exercises', loadChildren: './doc-exercises/doc-exercises.module#DocExercisesPageModule' },
{ path: 'doc-software', loadChildren: './doc-software/doc-software.module#DocSoftwarePageModule' },
{
path: 'semantics',
loadChildren: () => import('./semantics/semantics.module').then( m => m.SemanticsPageModule)
},
{ path: 'exercise', loadChildren: './exercise/exercise.module#ExercisePageModule' },
{ path: 'exercise-list', loadChildren: './exercise-list/exercise-list.module#ExerciseListPageModule' },
{ path: 'doc-voc-unit', loadChildren: './doc-voc-unit/doc-voc-unit.module#DocVocUnitPageModule' },
{ path: 'doc-exercises', loadChildren: './doc-exercises/doc-exercises.module#DocExercisesPageModule' },
{ path: 'doc-software', loadChildren: './doc-software/doc-software.module#DocSoftwarePageModule' },
{
path: 'semantics',
loadChildren: () => import('./semantics/semantics.module').then( m => m.SemanticsPageModule)
},
......
......@@ -8,14 +8,22 @@ import {StatusBar} from '@ionic-native/status-bar/ngx';
import {AppComponent} from './app.component';
import {HttpClientModule} from '@angular/common/http';
import {IonicStorageModule} from '@ionic/storage';
import {AppRoutingModule} from './app-routing.module';
import {TranslateTestingModule} from './translate-testing/translate-testing.module';
import {AppRoutingModule, routes} from './app-routing.module';
import {
FakeLoader,
TranslatePipeMock,
TranslateServiceStub,
TranslateTestingModule
} from './translate-testing/translate-testing.module';
import {APP_BASE_HREF} from '@angular/common';
import {Subscription} from 'rxjs';
import {HelperService} from './helper.service';
import {CorpusService} from './corpus.service';
import Spy = jasmine.Spy;
import MockMC from './models/mockMC';
import {LoadChildrenCallback, Route} from '@angular/router';
import configMC from '../configMC';
import {SemanticsPageModule} from './semantics/semantics.module';
describe('AppComponent', () => {
let statusBarSpy, splashScreenSpy, platformReadySpy, fixture: ComponentFixture<AppComponent>,
......@@ -92,6 +100,28 @@ describe('AppComponent', () => {
expect(languageSpy).toHaveBeenCalledTimes(1);
});
// TODO: add more tests!
it('should test routing', (done) => {
const semanticsRoute: Route = routes.find(x => x.path === configMC.pageUrlSemantics.slice(1));
const lcb: LoadChildrenCallback = semanticsRoute.loadChildren as LoadChildrenCallback;
const promise: Promise<any> = lcb() as Promise<any>;
promise.then((result: any) => {
expect(result).toBe(SemanticsPageModule);
done();
});
});
it('should test translations', (done) => {
const translateService: TranslateServiceStub = new TranslateServiceStub();
expect(translateService.getDefaultLang()).toBe('en');
translateService.get('key').subscribe((result: string) => {
expect(result).toBe('key');
const translatePipe: TranslatePipeMock = new TranslatePipeMock();
expect(translatePipe.transform('query')).toBe('query');
const translateLoader: FakeLoader = new FakeLoader();
translateLoader.getTranslation('en').subscribe((result2: any) => {
expect(Object.keys(result2).length).toBe(0);
done();
});
});
});
});
......@@ -6,7 +6,7 @@ import {RouterModule} from '@angular/router';
import {TranslateTestingModule} from './translate-testing/translate-testing.module';
import {APP_BASE_HREF} from '@angular/common';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {HttpClient} from '@angular/common/http';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {HelperService} from './helper.service';
import MockMC from './models/mockMC';
import {CaseValue, DependencyValue, ExerciseType, PartOfSpeechValue, Phenomenon} from './models/enum';
......@@ -118,6 +118,8 @@ describe('CorpusService', () => {
corpusService.availableCorpora = [];
const requestSpy: Spy = spyOn(helperService, 'makeGetRequest').and.returnValue(Promise.resolve(null));
const localStorageSpy: Spy = spyOn(corpusService, 'loadCorporaFromLocalStorage').and.returnValue(Promise.resolve());
spyOn(corpusService.storage, 'get').withArgs(configMC.localStorageKeyUpdateInfo).and.returnValue(
Promise.resolve(JSON.stringify(new UpdateInfo())));
corpusService.getCorpora().then(() => {
expect(localStorageSpy).toHaveBeenCalledTimes(1);
expect(corpusService.availableCorpora.length).toBe(0);
......@@ -136,10 +138,11 @@ describe('CorpusService', () => {
});
it('should get CTS text passage', (done) => {
const spy: Spy = spyOn(helperService, 'makeGetRequest').and.returnValue(Promise.reject(1));
const spy: Spy = spyOn(helperService, 'makeGetRequest').and.returnValue(Promise.reject(
new HttpErrorResponse({status: 500})));
corpusService.getCTStextPassage('').then(() => {
}, (error: number) => {
expect(error).toBe(1);
}, (error: HttpErrorResponse) => {
expect(error.status).toBe(500);
spy.and.returnValue(Promise.resolve(
(helperService.deepCopy(MockMC.applicationState) as ApplicationState).mostRecentSetup.annisResponse));
corpusService.getCTStextPassage('').then((ar: AnnisResponse) => {
......
......@@ -65,6 +65,8 @@ export class CorpusService {
feedback: new Feedback({general: '', incorrect: '', partiallyCorrect: '', correct: ''}),
instructionsTranslation: ''
});
public invalidQueryCorpusString: string;
public invalidSentenceCountString: string;
public invalidTextRangeString: string;
public isTextRangeCorrect = false;
public phenomenonMap: PhenomenonMap = new PhenomenonMap({
......@@ -291,6 +293,8 @@ export class CorpusService {
this.translate.get('DATA_ALREADY_SENT').subscribe(value => this.dataAlreadySentMessage = value);
this.translate.get('SEARCH_REGEX_MISSING').subscribe(value => this.searchRegexMissingString = value);
this.translate.get('TOO_MANY_SEARCH_RESULTS').subscribe(value => this.tooManyHitsString = value);
this.translate.get('INVALID_SENTENCE_COUNT').subscribe(value => this.invalidSentenceCountString = value);
this.translate.get('INVALID_QUERY_CORPUS').subscribe(value => this.invalidQueryCorpusString = value);
}
initCorpusService(): Promise<void> {
......
......@@ -33,7 +33,6 @@ export class ExerciseListPage implements OnInit {
public currentSearchValue: string;
public currentSortingCategory: SortingCategory = SortingCategory.dateDesc;
public exercises: ExerciseMC[] = [];
public ExerciseTypeTranslation = ExerciseTypeTranslation;
public hasVocChanged = false;
public Math = Math;
public metadata: { [eid: string]: string } = {};
......@@ -140,7 +139,7 @@ export class ExerciseListPage implements OnInit {
}
showExercise(exercise: ExerciseMC): Promise<void> {
return new Promise<void>((resolve, reject) => {
return new Promise<void>((resolve) => {
const url: string = configMC.backendBaseUrl + configMC.backendApiExercisePath;
const params: HttpParams = new HttpParams().set('eid', exercise.eid);
this.helperService.makeGetRequest(this.http, this.toastCtrl, url, params).then((ar: AnnisResponse) => {
......@@ -152,9 +151,8 @@ export class ExerciseListPage implements OnInit {
this.helperService.goToPreviewPage(this.navCtrl).then();
return resolve();
}, () => {
return reject();
return resolve();
});
}).catch(() => {
});
}
......
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {async, ComponentFixture, fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {ExerciseParametersPage} from './exercise-parameters.page';
import {HttpClientModule} from '@angular/common/http';
......@@ -106,19 +106,19 @@ describe('ExerciseParametersPage', () => {
});
it('should get exercise data', (done) => {
exerciseParametersPage.corpusService.initCurrentCorpus().then(() => {
exerciseParametersPage.corpusService.initCurrentCorpus().then(async () => {
exerciseParametersPage.corpusService.currentTextRange = new ReplaySubject<TextRange>(1);
exerciseParametersPage.corpusService.currentTextRange.next(new TextRange({start: ['', ''], end: ['', '']}));
const h5pSpy: Spy = spyOn(exerciseParametersPage, 'getH5Pexercise').and.returnValue(Promise.resolve());
const kwicSpy: Spy = spyOn(exerciseParametersPage, 'getKwicExercise').and.returnValue(Promise.resolve());
exerciseParametersPage.corpusService.exercise.type = ExerciseType.kwic;
exerciseParametersPage.getExerciseData();
await exerciseParametersPage.getExerciseData();
expect(kwicSpy).toHaveBeenCalledTimes(1);
exerciseParametersPage.corpusService.exercise.type = ExerciseType.markWords;
const pmc: PhenomenonMapContent = exerciseParametersPage.corpusService.phenomenonMap[Phenomenon.partOfSpeech];
pmc.translationValues = {};
pmc.translationValues[PartOfSpeechValue.adjective.toString()] = '';
exerciseParametersPage.getExerciseData();
await exerciseParametersPage.getExerciseData();
expect(h5pSpy).toHaveBeenCalledTimes(1);
done();
});
......
......@@ -60,8 +60,9 @@ export class ExerciseParametersPage implements OnInit {
return reject();
} else {
this.corpusService.annisResponse.solutions = null;
this.getExerciseData();
return resolve();
this.getExerciseData().then(() => {
return resolve();
});
}
});
}
......@@ -86,36 +87,40 @@ export class ExerciseParametersPage implements OnInit {
return translatedKey + ' (' + count + ')';
}
getExerciseData(): void {
const searchValues: string[] = this.corpusService.exercise.queryItems.map(
query => query.phenomenon + '=' + query.values.join('|'));
const formData = new FormData();
formData.append('urn', this.corpusService.currentUrn);
formData.append('search_values', JSON.stringify(searchValues));
let instructions: string = this.corpusService.exercise.instructionsTranslation;
if (this.corpusService.exercise.type === ExerciseType.kwic) {
this.getKwicExercise(formData).then();
return;
} else if (this.corpusService.exercise.type === ExerciseType.markWords) {
const phenomenon: Phenomenon = this.corpusService.exercise.queryItems[0].phenomenon;
const pmc: PhenomenonMapContent = this.corpusService.phenomenonMap[phenomenon];
const values: string[] = this.corpusService.exercise.queryItems[0].values as string[];
instructions += ` [${values.map(x => pmc.translationValues[x]).join(', ')}]`;
}
this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
// TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title
const workTitle: string = cc.title + ', ' + tr.start.filter(x => x).join('.') + '-' + tr.end.filter(x => x).join('.');
formData.append('work_title', workTitle);
formData.append('type', MoodleExerciseType[this.corpusService.exercise.type]);
formData.append('type_translation', this.corpusService.exercise.typeTranslation);
formData.append('instructions', instructions);
formData.append('correct_feedback', this.corpusService.exercise.feedback.correct);
formData.append('partially_correct_feedback', this.corpusService.exercise.feedback.partiallyCorrect);
formData.append('incorrect_feedback', this.corpusService.exercise.feedback.incorrect);
formData.append('general_feedback', this.corpusService.exercise.feedback.general);
formData.append('work_author', cc.author);
this.getH5Pexercise(formData).then();
getExerciseData(): Promise<void> {
return new Promise<void>(resolve => {
const searchValues: string[] = this.corpusService.exercise.queryItems.map(
query => query.phenomenon + '=' + query.values.join('|'));
const formData = new FormData();
formData.append('urn', this.corpusService.currentUrn);
formData.append('search_values', JSON.stringify(searchValues));
let instructions: string = this.corpusService.exercise.instructionsTranslation;
if (this.corpusService.exercise.type === ExerciseType.kwic) {
this.getKwicExercise(formData).then();
return resolve();
} else if (this.corpusService.exercise.type === ExerciseType.markWords) {
const phenomenon: Phenomenon = this.corpusService.exercise.queryItems[0].phenomenon;
const pmc: PhenomenonMapContent = this.corpusService.phenomenonMap[phenomenon];
const values: string[] = this.corpusService.exercise.queryItems[0].values as string[];
instructions += ` [${values.map(x => pmc.translationValues[x]).join(', ')}]`;
}
this.corpusService.currentCorpus.pipe(take(1)).subscribe((cc: CorpusMC) => {
this.corpusService.currentTextRange.pipe(take(1)).subscribe((tr: TextRange) => {
// TODO: change the corpus title to something meaningful, e.g. concatenate user ID and wanted exercise title
const workTitle: string = cc.title + ', ' + tr.start.filter(x => x).join('.') + '-' + tr.end.filter(x => x).join('.');
formData.append('work_title', workTitle);
formData.append('type', MoodleExerciseType[this.corpusService.exercise.type]);
formData.append('type_translation', this.corpusService.exercise.typeTranslation);
formData.append('instructions', instructions);
formData.append('correct_feedback', this.corpusService.exercise.feedback.correct);
formData.append('partially_correct_feedback', this.corpusService.exercise.feedback.partiallyCorrect);
formData.append('incorrect_feedback', this.corpusService.exercise.feedback.incorrect);
formData.append('general_feedback', this.corpusService.exercise.feedback.general);
formData.append('work_author', cc.author);
this.getH5Pexercise(formData).then(() => {
return resolve();
});
});
});
});
}
......
......@@ -3,11 +3,19 @@ import {TestBed} from '@angular/core/testing';
import {ExerciseService} from './exercise.service';
import {APP_BASE_HREF} from '@angular/common';
import configMC from '../configMC';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {IonicStorageModule} from '@ionic/storage';
import {TranslateTestingModule} from './translate-testing/translate-testing.module';
describe('ExerciseService', () => {
let exerciseService: ExerciseService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
IonicStorageModule.forRoot(),
TranslateTestingModule,
],
providers: [
{provide: APP_BASE_HREF, useValue: '/'},
],
......
/* tslint:disable:no-string-literal */
import {Injectable} from '@angular/core';
import configMC from '../configMC';
import {HelperService} from './helper.service';
import {ExercisePart} from './models/exercisePart';
declare var H5P: any;
// dirty hack to prevent H5P access errors after resize events
......@@ -15,6 +18,25 @@ window.onresize = () => {
providedIn: 'root'
})
export class ExerciseService {
// tslint:disable-next-line:variable-name
private _currentExerciseIndex: number;
get currentExerciseIndex(): number {
return this._currentExerciseIndex;
}
set currentExerciseIndex(value: number) {
this._currentExerciseIndex = value;
this.currentExercisePartIndex = [...Array(this.currentExerciseParts.length).keys()].find(
i => this.currentExerciseParts[i].startIndex <= this.currentExerciseIndex && (!this.currentExerciseParts[i + 1]
|| this.currentExerciseParts[i + 1].startIndex > this.currentExerciseIndex));
const cepi: number = this.currentExercisePartIndex;
this.currentExerciseName = this.currentExercisePartIndex ?
this.currentExerciseParts[cepi].exercises[this.currentExerciseIndex - this.currentExerciseParts[cepi].startIndex] : '';
}
public currentExerciseName: string;
public currentExercisePartIndex: number;
public currentExerciseParts: ExercisePart[];
public excludeOOV = false;
public fillBlanksString = 'fill_blanks';
public h5pContainerString = '.h5p-container';
......@@ -22,7 +44,7 @@ export class ExerciseService {
public kwicGraphs: string;
public vocListString = 'voc_list';
constructor() {
constructor(public helperService: HelperService) {
}
createGuid(): string {
......@@ -50,4 +72,9 @@ export class ExerciseService {
}, 50);
});
}
setH5Purl(url: string): void {
// this has to be LocalStorage because the H5P javascript cannot easily access the Ionic Storage
window.localStorage.setItem(configMC.localStorageKeyH5P, url);
}
}
......@@ -11,6 +11,7 @@ import {AnnisResponse} from '../models/annisResponse';
import {ExerciseType, MoodleExerciseType} from '../models/enum';
import Spy = jasmine.Spy;
import configMC from '../../configMC';
import MockMC from '../models/mockMC';
describe('ExercisePage', () => {
let exercisePage: ExercisePage;
......@@ -50,15 +51,19 @@ describe('ExercisePage', () => {
});
it('should be initialized', (done) => {
const loadExerciseSpy: Spy = spyOn(exercisePage, 'loadExercise');
const loadExerciseSpy: Spy = spyOn(exercisePage, 'loadExercise').and.returnValue(Promise.resolve());
checkSpy.and.callFake(() => Promise.reject());
exercisePage.ngOnInit().then(() => {
expect(loadExerciseSpy).toHaveBeenCalledTimes(0);
done();
checkSpy.and.returnValue(Promise.resolve());
exercisePage.ngOnInit().then(() => {
done();
});
});
});
it('should load the exercise', (done) => {
exercisePage.helperService.applicationState.next(exercisePage.helperService.deepCopy(MockMC.applicationState));
exercisePage.loadExercise().then(() => {
expect(exercisePage.corpusService.exercise.type).toBe(ExerciseType.cloze);
getRequestSpy.and.returnValue(Promise.resolve(new AnnisResponse({exercise_type: MoodleExerciseType.markWords.toString()})));
......
......@@ -114,25 +114,23 @@ describe('HelperService', () => {
const navFnArr: any[] = [helperService.goToAuthorDetailPage, helperService.goToDocExercisesPage, helperService.goToDocSoftwarePage,
helperService.goToDocVocUnitPage, helperService.goToExerciseListPage, helperService.goToExerciseParametersPage,
helperService.goToImprintPage, helperService.goToInfoPage, helperService.goToPreviewPage, helperService.goToSourcesPage,
helperService.goToTextRangePage, helperService.goToVocabularyCheckPage, helperService.goToKwicPage];
helperService.goToTextRangePage, helperService.goToVocabularyCheckPage, helperService.goToKwicPage,
helperService.goToRankingPage, helperService.goToSemanticsPage];
const pageUrlArr: string[] = [configMC.pageUrlAuthorDetail, configMC.pageUrlDocExercises, configMC.pageUrlDocSoftware,
configMC.pageUrlDocVocUnit, configMC.pageUrlExerciseList, configMC.pageUrlExerciseParameters, configMC.pageUrlImprint,
configMC.pageUrlInfo, configMC.pageUrlPreview, configMC.pageUrlSources, configMC.pageUrlTextRange,
configMC.pageUrlVocabularyCheck, configMC.pageUrlKwic];
checkNavigation(navFnArr, pageUrlArr, navCtrl, forwardSpy).then(() => {
helperService.goToAuthorPage(navCtrl).then(() => {
expect(helperService.isVocabularyCheck).toBeFalsy();
helperService.goToShowTextPage(navCtrl, true).then(() => {
expect(helperService.isVocabularyCheck).toBe(true);
const rootSpy: Spy = spyOn(navCtrl, 'navigateRoot').and.returnValue(Promise.resolve(true));
helperService.goToHomePage(navCtrl).then(() => {
expect(rootSpy).toHaveBeenCalledWith(configMC.pageUrlHome);
helperService.goToTestPage(navCtrl).then(() => {
expect(rootSpy).toHaveBeenCalledWith(configMC.pageUrlTest);
done();
});
});
});
configMC.pageUrlVocabularyCheck, configMC.pageUrlKwic, configMC.pageUrlRanking, configMC.pageUrlSemantics];
checkNavigation(navFnArr, pageUrlArr, navCtrl, forwardSpy).then(async () => {
await helperService.goToAuthorPage(navCtrl);
expect(helperService.isVocabularyCheck).toBeFalsy();
await helperService.goToShowTextPage(navCtrl, true);
expect(helperService.isVocabularyCheck).toBe(true);
const rootSpy: Spy = spyOn(navCtrl, 'navigateRoot').and.returnValue(Promise.resolve(true));
await helperService.goToHomePage(navCtrl);
expect(rootSpy).toHaveBeenCalledWith(configMC.pageUrlHome);
helperService.goToTestPage(navCtrl).then(() => {
expect(rootSpy).toHaveBeenCalledWith(configMC.pageUrlTest);
done();
});
});
});
......
......@@ -233,6 +233,10 @@ export class HelperService {
return navCtrl.navigateForward(configMC.pageUrlPreview);
}
goToRankingPage(navCtrl: NavController): Promise<boolean> {
return navCtrl.navigateForward(configMC.pageUrlRanking);
}
goToSemanticsPage(navCtrl: NavController): Promise<boolean> {
return navCtrl.navigateForward(configMC.pageUrlSemantics);
}
......
/* tslint:disable:variable-name */
import {Citation} from 'src/app/models/citation';
export class CorpusMC {
......
......@@ -10,6 +10,8 @@ import {TestResultMC} from './testResultMC';
import StatementBase from './xAPI/StatementBase';
import Result from './xAPI/Result';
import Score from './xAPI/Score';
import {TextRange} from './textRange';
import {Citation} from './citation';
export default class MockMC {
static apiResponseCorporaGet: object = {
......@@ -19,13 +21,6 @@ export default class MockMC {
title: 'title',
})]
};
static apiResponseExerciseListGet: ExerciseMC[] = [new ExerciseMC({
eid: 'eid',
exercise_type: MoodleExerciseType.cloze.toString(),
exercise_type_translation: 'exercise_type_translation',
work_author: 'work_author',
work_title: 'work_title',
})];
static apiResponseFrequencyAnalysisGet: FrequencyItem[] = [new FrequencyItem({
phenomena: [Phenomenon.partOfSpeech.toString()],
values: [PartOfSpeechValue.adjective.toString()]
......@@ -35,7 +30,10 @@ export default class MockMC {
links: []
});
static applicationState: ApplicationState = new ApplicationState({
currentSetup: new TextData({currentCorpus: new CorpusMC()}),
currentSetup: new TextData({
currentCorpus: new CorpusMC({citations: {}}),
currentTextRange: new TextRange({start: ['1', '2'], end: ['1', '2']})
}),
mostRecentSetup: new TextData({annisResponse: new AnnisResponse({nodes: [new NodeMC()], links: []})}),
exerciseList: [new ExerciseMC()]
});
......
......@@ -29,6 +29,7 @@ describe('PreviewPage', () => {
let fixture: ComponentFixture<PreviewPage>;
let corpusService: CorpusService;
let checkAnnisResponseSpy: Spy;
let xapiSpy: Spy;
beforeEach(async(() => {
TestBed.configureTestingModule({
......@@ -50,6 +51,7 @@ describe('PreviewPage', () => {
corpusService = TestBed.inject(CorpusService);
fixture = TestBed.createComponent(PreviewPage);
previewPage = fixture.componentInstance;
xapiSpy = spyOn(previewPage, 'setXAPIeventHandler');
checkAnnisResponseSpy = spyOn(corpusService, 'checkAnnisResponse').and.callFake(() => Promise.reject());
fixture.detectChanges();
}));
......@@ -93,9 +95,10 @@ describe('PreviewPage', () => {
body.appendChild(iframe);
spyOn(previewPage, 'sendData').and.returnValue(Promise.resolve());
previewPage.ngOnDestroy();
const oldDispatcher: any = previewPage.helperService.deepCopy(H5P.externalDispatcher);
const newDispatcher: H5PeventDispatcherMock = new H5PeventDispatcherMock();
const oldDispatcher: any = previewPage.helperService.deepCopy(H5P.externalDispatcher);
H5P.externalDispatcher = newDispatcher;
xapiSpy.and.callThrough();
previewPage.ngOnInit().then(() => {
newDispatcher.triggerXAPI(configMC.xAPIverbIDanswered, new Result());
checkAnnisResponseSpy.and.returnValue(Promise.resolve());
......
......@@ -58,8 +58,7 @@ export class PreviewPage implements OnDestroy, OnInit {
// this will be called via GET request from the h5p standalone javascript library
const url: string = `${configMC.backendBaseUrl + configMC.backendApiH5pPath}` +
`?eid=${this.corpusService.annisResponse.exercise_id}&lang=${this.translateService.currentLang + solutionIndicesString}`;
// this has to be LocalStorage because the H5P javascript cannot easily access the Ionic Storage
window.localStorage.setItem(configMC.localStorageKeyH5P, url);
this.exerciseService.setH5Purl(url);
const exerciseTypePath: string = this.corpusService.exercise.type === ExerciseType.markWords ? 'mark_words' : 'drag_text';
this.exerciseService.initH5P(exerciseTypePath).then();
this.updateFileUrl();
......@@ -75,21 +74,7 @@ export class PreviewPage implements OnDestroy, OnInit {
if (!this.helperService.isVocabularyCheck) {
this.exerciseService.excludeOOV = false;
}
H5P.externalDispatcher.on('xAPI', (event: XAPIevent) => {
// results are only available when a task has been completed/answered, not in the "attempted" or "interacted" stages
if (event.data.statement.verb.id === configMC.xAPIverbIDanswered && event.data.statement.result) {
const iframe: HTMLIFrameElement = document.querySelector(this.exerciseService.h5pIframeString);
if (iframe) {
const iframeDoc: Document = iframe.contentWindow.document;
const inner: string = iframeDoc.documentElement.innerHTML;
const result: TestResultMC = new TestResultMC({
statement: event.data.statement,