@testgorilla/tgo-coding-test 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +45 -0
- package/README.md +257 -0
- package/jest.config.ts +21 -0
- package/ng-package.json +14 -0
- package/package.json +33 -0
- package/project.json +36 -0
- package/src/assets/i18n/en.json +124 -0
- package/src/index.ts +30 -0
- package/src/lib/components/.gitkeep +0 -0
- package/src/lib/components/code-editor/code-editor.component.html +10 -0
- package/src/lib/components/code-editor/code-editor.component.scss +21 -0
- package/src/lib/components/code-editor/code-editor.component.spec.ts +136 -0
- package/src/lib/components/code-editor/code-editor.component.ts +369 -0
- package/src/lib/components/code-editor/code-editor.mocks.ts +28 -0
- package/src/lib/components/code-editor/code-editor.service.spec.ts +160 -0
- package/src/lib/components/code-editor/code-editor.service.ts +94 -0
- package/src/lib/components/code-editor/helpers/c-helper.spec.ts +39 -0
- package/src/lib/components/code-editor/helpers/c-helper.ts +51 -0
- package/src/lib/components/code-editor/helpers/code-editor-helper.base.spec.ts +30 -0
- package/src/lib/components/code-editor/helpers/code-editor-helper.base.ts +16 -0
- package/src/lib/components/code-editor/helpers/code-editor-helper.mocks.ts +24 -0
- package/src/lib/components/code-editor/helpers/code-editor-helper.model.ts +67 -0
- package/src/lib/components/code-editor/helpers/cpp-helper.spec.ts +40 -0
- package/src/lib/components/code-editor/helpers/cpp-helper.ts +52 -0
- package/src/lib/components/code-editor/helpers/csharp-helper.spec.ts +42 -0
- package/src/lib/components/code-editor/helpers/csharp-helper.ts +55 -0
- package/src/lib/components/code-editor/helpers/go-helper.spec.ts +41 -0
- package/src/lib/components/code-editor/helpers/go-helper.ts +54 -0
- package/src/lib/components/code-editor/helpers/index.ts +15 -0
- package/src/lib/components/code-editor/helpers/java-helper.spec.ts +41 -0
- package/src/lib/components/code-editor/helpers/java-helper.ts +54 -0
- package/src/lib/components/code-editor/helpers/javascript-helper.spec.ts +39 -0
- package/src/lib/components/code-editor/helpers/javascript-helper.ts +32 -0
- package/src/lib/components/code-editor/helpers/kotlin-helper.spec.ts +41 -0
- package/src/lib/components/code-editor/helpers/kotlin-helper.ts +54 -0
- package/src/lib/components/code-editor/helpers/php-helper.spec.ts +39 -0
- package/src/lib/components/code-editor/helpers/php-helper.ts +32 -0
- package/src/lib/components/code-editor/helpers/python-helper.spec.ts +39 -0
- package/src/lib/components/code-editor/helpers/python-helper.ts +32 -0
- package/src/lib/components/code-editor/helpers/r-helper.spec.ts +39 -0
- package/src/lib/components/code-editor/helpers/r-helper.ts +32 -0
- package/src/lib/components/code-editor/helpers/ruby-helper.spec.ts +39 -0
- package/src/lib/components/code-editor/helpers/ruby-helper.ts +32 -0
- package/src/lib/components/code-editor/helpers/scala-helper.spec.ts +41 -0
- package/src/lib/components/code-editor/helpers/scala-helper.ts +53 -0
- package/src/lib/components/code-editor/helpers/sql-helper.spec.ts +87 -0
- package/src/lib/components/code-editor/helpers/sql-helper.ts +44 -0
- package/src/lib/components/code-editor/helpers/swift-helper.spec.ts +40 -0
- package/src/lib/components/code-editor/helpers/swift-helper.ts +51 -0
- package/src/lib/components/code-editor/helpers/typescript-helper.spec.ts +40 -0
- package/src/lib/components/code-editor/helpers/typescript-helper.ts +52 -0
- package/src/lib/components/code-editor/models/code-editor.model.ts +9 -0
- package/src/lib/components/code-editor/models/coding-snapshot.model.ts +4 -0
- package/src/lib/components/coding-question/coding-question.component.html +78 -0
- package/src/lib/components/coding-question/coding-question.component.scss +76 -0
- package/src/lib/components/coding-question/coding-question.component.spec.ts +85 -0
- package/src/lib/components/coding-question/coding-question.component.ts +102 -0
- package/src/lib/components/coding-section/coding-section.component.html +82 -0
- package/src/lib/components/coding-section/coding-section.component.scss +64 -0
- package/src/lib/components/coding-section/coding-section.component.spec.ts +257 -0
- package/src/lib/components/coding-section/coding-section.component.ts +187 -0
- package/src/lib/components/coding-test.module.ts +124 -0
- package/src/lib/components/common/truncated-text/truncated-text.component.html +6 -0
- package/src/lib/components/common/truncated-text/truncated-text.component.scss +18 -0
- package/src/lib/components/common/truncated-text/truncated-text.component.spec.ts +84 -0
- package/src/lib/components/common/truncated-text/truncated-text.component.ts +37 -0
- package/src/lib/components/configurations/configurations.component.html +57 -0
- package/src/lib/components/configurations/configurations.component.scss +42 -0
- package/src/lib/components/configurations/configurations.component.spec.ts +186 -0
- package/src/lib/components/configurations/configurations.component.ts +98 -0
- package/src/lib/components/instructions/instructions.component.html +41 -0
- package/src/lib/components/instructions/instructions.component.scss +167 -0
- package/src/lib/components/instructions/instructions.component.spec.ts +106 -0
- package/src/lib/components/instructions/instructions.component.ts +138 -0
- package/src/lib/components/panel/panel.component.html +19 -0
- package/src/lib/components/panel/panel.component.scss +41 -0
- package/src/lib/components/panel/panel.component.spec.ts +40 -0
- package/src/lib/components/panel/panel.component.ts +34 -0
- package/src/lib/components/runnable-editor/runnable-editor.component.html +75 -0
- package/src/lib/components/runnable-editor/runnable-editor.component.scss +55 -0
- package/src/lib/components/runnable-editor/runnable-editor.component.spec.ts +124 -0
- package/src/lib/components/runnable-editor/runnable-editor.component.ts +155 -0
- package/src/lib/components/tests/test-cases/test-cases.component.html +135 -0
- package/src/lib/components/tests/test-cases/test-cases.component.scss +220 -0
- package/src/lib/components/tests/test-cases/test-cases.component.spec.ts +401 -0
- package/src/lib/components/tests/test-cases/test-cases.component.ts +205 -0
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.html +94 -0
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.scss +103 -0
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.spec.ts +122 -0
- package/src/lib/components/tests/test-cases-content/test-cases-content.component.ts +102 -0
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.html +16 -0
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.scss +49 -0
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.spec.ts +22 -0
- package/src/lib/components/tests/test-cases-status/test-cases-status.component.ts +18 -0
- package/src/lib/components/tests/test-results.component.html +119 -0
- package/src/lib/components/tests/test-results.component.scss +189 -0
- package/src/lib/components/tests/test-results.component.spec.ts +140 -0
- package/src/lib/components/tests/test-results.component.ts +98 -0
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.html +96 -0
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.scss +6 -0
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.spec.ts +599 -0
- package/src/lib/components/tgo-coding-test/tgo-coding-test.component.ts +279 -0
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.html +36 -0
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.scss +183 -0
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.spec.ts +883 -0
- package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.ts +575 -0
- package/src/lib/config/index.ts +3 -0
- package/src/lib/config/tgo-coding-test.config.ts +26 -0
- package/src/lib/config/tgo-coding-test.provider.ts +38 -0
- package/src/lib/config/tgo-coding-test.token.ts +21 -0
- package/src/lib/models/.gitkeep +0 -0
- package/src/lib/models/auto-saved-data.ts +51 -0
- package/src/lib/models/code-event.ts +17 -0
- package/src/lib/models/coderunner-execution-results.ts +58 -0
- package/src/lib/models/coding-lib.mocks.ts +246 -0
- package/src/lib/models/configs.ts +18 -0
- package/src/lib/models/language-change-action.ts +4 -0
- package/src/lib/models/lat-languages.ts +12 -0
- package/src/lib/models/mixpanel-events.ts +3 -0
- package/src/lib/models/mode.ts +5 -0
- package/src/lib/models/paste-data.ts +4 -0
- package/src/lib/models/programming-language.ts +9 -0
- package/src/lib/models/test-cases.ts +74 -0
- package/src/lib/models/theme.ts +5 -0
- package/src/lib/models/translations.ts +1 -0
- package/src/lib/models/view-mode.ts +6 -0
- package/src/lib/pipes/memoize-func.pipe.ts +34 -0
- package/src/lib/services/.gitkeep +0 -0
- package/src/lib/services/candidate-coding-test-services/candidature-api.service.spec.ts +40 -0
- package/src/lib/services/candidate-coding-test-services/candidature-api.service.ts +15 -0
- package/src/lib/services/candidate-coding-test-services/coderunner-api.service.spec.ts +134 -0
- package/src/lib/services/candidate-coding-test-services/coderunner-api.service.ts +105 -0
- package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.spec.ts +161 -0
- package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.ts +100 -0
- package/src/lib/services/candidate-coding-test-services/coding-test.service.spec.ts +1524 -0
- package/src/lib/services/candidate-coding-test-services/coding-test.service.ts +843 -0
- package/src/lib/services/candidate-coding-test-services/index.ts +4 -0
- package/src/lib/services/coding-test-config.service.ts +48 -0
- package/src/lib/services/configurations.service.mocks.ts +77 -0
- package/src/lib/services/configurations.service.spec.ts +79 -0
- package/src/lib/services/configurations.service.ts +111 -0
- package/src/lib/services/index.ts +0 -0
- package/src/lib/services/lib-coding-test.service.spec.ts +265 -0
- package/src/lib/services/lib-coding-test.service.ts +157 -0
- package/src/lib/services/local-storage.service.mocks.ts +22 -0
- package/src/lib/services/storage.service.spec.ts +1120 -0
- package/src/lib/services/storage.service.ts +729 -0
- package/src/lib/services/test-cases.service.spec.ts +53 -0
- package/src/lib/services/test-cases.service.ts +29 -0
- package/src/lib/services/theme.service.spec.ts +76 -0
- package/src/lib/services/theme.service.ts +34 -0
- package/src/lib/styles/mixins.scss +86 -0
- package/src/lib/styles/styles.scss +112 -0
- package/src/lib/styles/variables.scss +105 -0
- package/src/lib/utils/.gitkeep +0 -0
- package/src/lib/utils/additional-languages/erlang.ts +115 -0
- package/src/lib/utils/resize-element.ts +15 -0
- package/src/lib/utils/time-to-ms.util.ts +10 -0
- package/src/test-setup.ts +1 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +12 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +13 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
import { NO_ERRORS_SCHEMA, SimpleChange, SimpleChanges } from '@angular/core';
|
|
2
|
+
import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
|
|
3
|
+
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|
4
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
5
|
+
import { MockProvider, MockProviders } from 'ng-mocks';
|
|
6
|
+
import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
|
|
7
|
+
import { ReplaySubject, Subject } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
import { TgoCodingTestComponent } from './tgo-coding-test.component';
|
|
10
|
+
import { CodeEditorLanguages } from '../code-editor/helpers/code-editor-helper.model';
|
|
11
|
+
import { AssessmentIdPreview } from '../../models/lat-languages';
|
|
12
|
+
import { Modes } from '../../models/mode';
|
|
13
|
+
import { ViewMode } from '../../models/view-mode';
|
|
14
|
+
import { ConfigurationsService } from '../../services/configurations.service';
|
|
15
|
+
import { CONFIGURATIONS_SERVICE_MOCK } from '../../services/configurations.service.mocks';
|
|
16
|
+
import { LibCodingTestService } from '../../services/lib-coding-test.service';
|
|
17
|
+
import { StorageCodingService } from '../../services/storage.service';
|
|
18
|
+
import { TestCasesService } from '../../services/test-cases.service';
|
|
19
|
+
import { ThemeService } from '../../services/theme.service';
|
|
20
|
+
|
|
21
|
+
describe('TgoCodingTestComponent', () => {
|
|
22
|
+
let component: TgoCodingTestComponent;
|
|
23
|
+
let fixture: ComponentFixture<TgoCodingTestComponent>;
|
|
24
|
+
let storageCodingService: StorageCodingService;
|
|
25
|
+
let configurationsService: ConfigurationsService;
|
|
26
|
+
let libCodingTestService: LibCodingTestService;
|
|
27
|
+
let setupAutoSavedDataSpy: jest.SpyInstance;
|
|
28
|
+
let initializeSavingSpy: jest.SpyInstance;
|
|
29
|
+
let setCodeComponentDestroyedSpy: jest.SpyInstance;
|
|
30
|
+
let changeCurrentLanguageSpy: jest.SpyInstance;
|
|
31
|
+
let setVersionSpy: jest.SpyInstance;
|
|
32
|
+
let setInitCodeSpy: jest.SpyInstance;
|
|
33
|
+
let changeLanguageSpy: jest.SpyInstance;
|
|
34
|
+
let updateInitCodeSpy: jest.SpyInstance;
|
|
35
|
+
const questionId = 12345;
|
|
36
|
+
|
|
37
|
+
beforeEach(waitForAsync(() => {
|
|
38
|
+
TestBed.configureTestingModule({
|
|
39
|
+
imports: [TgoCodingTestComponent, MonacoEditorModule.forRoot(), NoopAnimationsModule],
|
|
40
|
+
schemas: [NO_ERRORS_SCHEMA],
|
|
41
|
+
providers: [
|
|
42
|
+
MockProviders(StorageCodingService),
|
|
43
|
+
MockProvider(TestCasesService, {
|
|
44
|
+
activeTestCaseIndex$: new ReplaySubject(1),
|
|
45
|
+
setActiveTestCase: jest.fn(),
|
|
46
|
+
createTestCaseLocalId: jest.fn(),
|
|
47
|
+
updateTestCaseLocalId: jest.fn(),
|
|
48
|
+
resetLastTestCaseLocalId: jest.fn(),
|
|
49
|
+
}),
|
|
50
|
+
MockProvider(ThemeService, {
|
|
51
|
+
themeColors$: new ReplaySubject(1),
|
|
52
|
+
companyColor: '#46a997',
|
|
53
|
+
}),
|
|
54
|
+
MockProvider(ConfigurationsService, CONFIGURATIONS_SERVICE_MOCK),
|
|
55
|
+
MockProvider(DomSanitizer, {
|
|
56
|
+
bypassSecurityTrustResourceUrl: val => val,
|
|
57
|
+
bypassSecurityTrustHtml: val => val,
|
|
58
|
+
sanitize: (context, value) => (typeof value === 'string' ? value : null),
|
|
59
|
+
}),
|
|
60
|
+
MockProvider(LibCodingTestService, {
|
|
61
|
+
clearSavedCode$: new Subject(),
|
|
62
|
+
triggerClearSavedCode(): void {
|
|
63
|
+
this.clearSavedCode$.next(true);
|
|
64
|
+
},
|
|
65
|
+
clearLastLang$: new Subject(),
|
|
66
|
+
currentLanguage$: new ReplaySubject(1),
|
|
67
|
+
changeCurrentLanguage(value: CodeEditorLanguages): void {
|
|
68
|
+
this.currentLanguage$.next(value);
|
|
69
|
+
},
|
|
70
|
+
languageChange$: new Subject(),
|
|
71
|
+
codeReset$: new Subject(),
|
|
72
|
+
themeChanged$: new ReplaySubject(1),
|
|
73
|
+
testCaseDeletion$: new Subject(),
|
|
74
|
+
setInitCode: jest.fn(),
|
|
75
|
+
setVersion: jest.fn(),
|
|
76
|
+
getVersion: jest.fn().mockReturnValue('1.0'),
|
|
77
|
+
isFullscreen$: new ReplaySubject(1),
|
|
78
|
+
setFullscreen(value: boolean): void {
|
|
79
|
+
this.isFullscreen$.next(value);
|
|
80
|
+
},
|
|
81
|
+
updateTestCases: jest.fn(),
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
})
|
|
85
|
+
.overrideComponent(TgoCodingTestComponent, {
|
|
86
|
+
set: {
|
|
87
|
+
template: '',
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
.compileComponents();
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
fixture = TestBed.createComponent(TgoCodingTestComponent);
|
|
95
|
+
component = fixture.componentInstance;
|
|
96
|
+
storageCodingService = TestBed.inject(StorageCodingService);
|
|
97
|
+
configurationsService = TestBed.inject(ConfigurationsService);
|
|
98
|
+
libCodingTestService = TestBed.inject(LibCodingTestService);
|
|
99
|
+
updateInitCodeSpy = jest.spyOn(component, 'updateInitCode');
|
|
100
|
+
setupAutoSavedDataSpy = jest.spyOn(storageCodingService, 'setupAutoSavedData');
|
|
101
|
+
initializeSavingSpy = jest.spyOn(storageCodingService, 'initializeSaving');
|
|
102
|
+
changeLanguageSpy = jest.spyOn(storageCodingService, 'changeLanguage');
|
|
103
|
+
changeCurrentLanguageSpy = jest.spyOn(libCodingTestService, 'changeCurrentLanguage');
|
|
104
|
+
setVersionSpy = jest.spyOn(libCodingTestService, 'setVersion');
|
|
105
|
+
setInitCodeSpy = jest.spyOn(libCodingTestService, 'setInitCode');
|
|
106
|
+
setCodeComponentDestroyedSpy = jest.spyOn(configurationsService, 'setCodeComponentDestroyed');
|
|
107
|
+
component.viewMode = ViewMode.Full;
|
|
108
|
+
component.languages = [
|
|
109
|
+
{
|
|
110
|
+
value: CodeEditorLanguages.Python,
|
|
111
|
+
label: 'python',
|
|
112
|
+
version: '1.23',
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
component.assessmentId = 'abc-def-ghi';
|
|
116
|
+
component.mode = Modes.Running;
|
|
117
|
+
component.initCode = 'sample python code';
|
|
118
|
+
component.questionId = questionId;
|
|
119
|
+
component.isLAT = true;
|
|
120
|
+
component.translations = {
|
|
121
|
+
HEADINGS: {
|
|
122
|
+
INSTRUCTIONS: 'Instructions',
|
|
123
|
+
CODING: 'Coding Window',
|
|
124
|
+
CONFIGURATIONS: 'Configurations',
|
|
125
|
+
FORMATTING: 'Formatting',
|
|
126
|
+
CODING_ASSISTANCE: 'Coding Assistance',
|
|
127
|
+
TESTS: 'Tests',
|
|
128
|
+
},
|
|
129
|
+
TOOLTIPS: {
|
|
130
|
+
RESET_CODE: 'Reset code',
|
|
131
|
+
HELP: 'Help',
|
|
132
|
+
MAXIMISE: 'Click to view code-runner in full-screen',
|
|
133
|
+
MINIMIZE: 'Minimize',
|
|
134
|
+
CONFIGURATIONS: 'Configurations',
|
|
135
|
+
},
|
|
136
|
+
TEST_RESULTS: {
|
|
137
|
+
RUN_TESTS: 'Run tests',
|
|
138
|
+
TEST_CASES: {
|
|
139
|
+
ADD_TEST_CASE: 'Add Test Case',
|
|
140
|
+
INPUT: 'Input',
|
|
141
|
+
EXPECTED_OUTPUT: 'Expected output',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
CODE_QUESTION: {
|
|
145
|
+
LANGUAGE_USING: "For this test you're using",
|
|
146
|
+
},
|
|
147
|
+
MODALS: {
|
|
148
|
+
RESET_CODE: {
|
|
149
|
+
TITLE: 'Are you sure you want to reset your code?',
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
fixture.detectChanges();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('when initialized', () => {
|
|
158
|
+
it('should set language in libCodingTestService', () => {
|
|
159
|
+
expect(changeCurrentLanguageSpy).toBeCalledWith(component.languages[0].value);
|
|
160
|
+
});
|
|
161
|
+
it('if version is available, it should set version in libCodingTestService', () => {
|
|
162
|
+
expect(setVersionSpy).toBeCalledWith(component.languages[0].version);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should set isFullViewMode to true if viewMode === ViewMode.Full', () => {
|
|
166
|
+
expect(component.isFullViewMode).toEqual(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('when performing local storage setup in cadidate environment', () => {
|
|
170
|
+
let clearSavedCodeSpy: jest.SpyInstance;
|
|
171
|
+
let clearSavedTestCasesSpy: jest.SpyInstance;
|
|
172
|
+
beforeEach(() => {
|
|
173
|
+
clearSavedCodeSpy = jest.spyOn(storageCodingService, 'clearSavedCode');
|
|
174
|
+
clearSavedTestCasesSpy = jest.spyOn(storageCodingService, 'clearSavedTestCases');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should pass the language, actual assessment ID, Running mode check to setupAutoSavedData', () => {
|
|
178
|
+
expect(setupAutoSavedDataSpy).toBeCalledWith(
|
|
179
|
+
component.languages[0].value,
|
|
180
|
+
component.assessmentId,
|
|
181
|
+
String(questionId),
|
|
182
|
+
component.mode === Modes.Running,
|
|
183
|
+
component.mode === Modes.Running && component.isLAT,
|
|
184
|
+
component.isLAT,
|
|
185
|
+
component.mode
|
|
186
|
+
);
|
|
187
|
+
expect(setCodeComponentDestroyedSpy).toBeCalledWith(false);
|
|
188
|
+
expect(updateInitCodeSpy).toBeCalled();
|
|
189
|
+
expect(initializeSavingSpy).toBeCalled();
|
|
190
|
+
});
|
|
191
|
+
describe('when the test is LAT', () => {
|
|
192
|
+
beforeEach(() => {
|
|
193
|
+
component.isLAT = true;
|
|
194
|
+
setupAutoSavedDataSpy.mockReset();
|
|
195
|
+
});
|
|
196
|
+
it('should pass the language, assessment ID, true to codeSaveEnabled, false to testCasesSaveEnabled and true to isLAT if the mode is Modes.Preview', () => {
|
|
197
|
+
component.mode = Modes.Preview;
|
|
198
|
+
component.ngOnInit();
|
|
199
|
+
expect(setupAutoSavedDataSpy).toBeCalledWith(
|
|
200
|
+
component.languages[0].value,
|
|
201
|
+
component.assessmentId,
|
|
202
|
+
String(questionId),
|
|
203
|
+
true,
|
|
204
|
+
false,
|
|
205
|
+
true,
|
|
206
|
+
Modes.Preview
|
|
207
|
+
);
|
|
208
|
+
expect(setCodeComponentDestroyedSpy).toBeCalledWith(false);
|
|
209
|
+
expect(updateInitCodeSpy).toBeCalled();
|
|
210
|
+
expect(initializeSavingSpy).toBeCalled();
|
|
211
|
+
});
|
|
212
|
+
it('should pass the language, preview assessment ID, true to codeSaveEnabled, false to testCasesSaveEnabled and true to isLAT if the mode is Modes.NonAssessmentPreview', () => {
|
|
213
|
+
setupAutoSavedDataSpy.mockReset();
|
|
214
|
+
component.mode = Modes.NonAssessmentPreview;
|
|
215
|
+
component.ngOnInit();
|
|
216
|
+
expect(setupAutoSavedDataSpy).toBeCalledWith(
|
|
217
|
+
component.languages[0].value,
|
|
218
|
+
AssessmentIdPreview,
|
|
219
|
+
String(questionId),
|
|
220
|
+
true,
|
|
221
|
+
false,
|
|
222
|
+
true,
|
|
223
|
+
Modes.NonAssessmentPreview
|
|
224
|
+
);
|
|
225
|
+
expect(setCodeComponentDestroyedSpy).toBeCalledWith(false);
|
|
226
|
+
expect(updateInitCodeSpy).toBeCalled();
|
|
227
|
+
expect(initializeSavingSpy).toBeCalled();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should pass the language, actual assessment ID, true to codeSaveEnabled, true to testCasesSaveEnabled and true to isLAT if the mode is Modes.Running', () => {
|
|
231
|
+
setupAutoSavedDataSpy.mockReset();
|
|
232
|
+
component.mode = Modes.Running;
|
|
233
|
+
component.ngOnInit();
|
|
234
|
+
expect(setupAutoSavedDataSpy).toBeCalledWith(
|
|
235
|
+
component.languages[0].value,
|
|
236
|
+
component.assessmentId,
|
|
237
|
+
String(questionId),
|
|
238
|
+
true,
|
|
239
|
+
true,
|
|
240
|
+
true,
|
|
241
|
+
Modes.Running
|
|
242
|
+
);
|
|
243
|
+
expect(setCodeComponentDestroyedSpy).toBeCalledWith(false);
|
|
244
|
+
expect(updateInitCodeSpy).toBeCalled();
|
|
245
|
+
expect(initializeSavingSpy).toBeCalled();
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should call clearSavedCode() and clearSavedTestCases() if libCodingTestService.clearSavedCode$ is emitted', fakeAsync(() => {
|
|
249
|
+
component.mode = Modes.Preview;
|
|
250
|
+
component.ngOnInit();
|
|
251
|
+
libCodingTestService.triggerClearSavedCode();
|
|
252
|
+
tick();
|
|
253
|
+
|
|
254
|
+
expect(clearSavedCodeSpy).toHaveBeenCalled();
|
|
255
|
+
expect(clearSavedTestCasesSpy).toHaveBeenCalled();
|
|
256
|
+
}));
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe('and when mode is Running', () => {
|
|
260
|
+
beforeEach(() => {
|
|
261
|
+
component.mode = Modes.Running;
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it('should call clearSavedCode() if libCodingTestService.clearSavedCode$ is emitted', fakeAsync(() => {
|
|
265
|
+
component.ngOnInit();
|
|
266
|
+
libCodingTestService.triggerClearSavedCode();
|
|
267
|
+
tick();
|
|
268
|
+
|
|
269
|
+
expect(clearSavedCodeSpy).toHaveBeenCalled();
|
|
270
|
+
}));
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('and when isLAT is true', () => {
|
|
274
|
+
let clearLastLangSpy: jest.SpyInstance;
|
|
275
|
+
|
|
276
|
+
beforeEach(() => {
|
|
277
|
+
component.isLAT = true;
|
|
278
|
+
clearLastLangSpy = jest.spyOn(storageCodingService, 'clearLastLang');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should call clearLastLang() if libCodingTestService.clearLastLang$ is emitted', fakeAsync(() => {
|
|
282
|
+
component.ngOnInit();
|
|
283
|
+
(libCodingTestService.clearLastLang$ as Subject<any>).next(true);
|
|
284
|
+
tick();
|
|
285
|
+
|
|
286
|
+
expect(clearLastLangSpy).toHaveBeenCalled();
|
|
287
|
+
}));
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
describe('when performPeriodicMaintenance is called', () => {
|
|
292
|
+
let performMaintenanceAndCleanupSpy: jest.SpyInstance;
|
|
293
|
+
let originalLocalStorage: Storage;
|
|
294
|
+
let mockLocalStorage: { getItem: jest.Mock; setItem: jest.Mock; clear: jest.Mock };
|
|
295
|
+
let randomSpy: jest.SpyInstance;
|
|
296
|
+
|
|
297
|
+
beforeEach(() => {
|
|
298
|
+
performMaintenanceAndCleanupSpy = jest.spyOn(storageCodingService, 'performMaintenanceAndCleanup');
|
|
299
|
+
|
|
300
|
+
// Save the original localStorage
|
|
301
|
+
originalLocalStorage = window.localStorage;
|
|
302
|
+
|
|
303
|
+
// Create a mock localStorage
|
|
304
|
+
mockLocalStorage = {
|
|
305
|
+
getItem: jest.fn(),
|
|
306
|
+
setItem: jest.fn(),
|
|
307
|
+
clear: jest.fn(),
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// Replace localStorage with our mock
|
|
311
|
+
Object.defineProperty(window, 'localStorage', {
|
|
312
|
+
value: mockLocalStorage,
|
|
313
|
+
writable: true,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
randomSpy = jest.spyOn(Math, 'random');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
afterEach(() => {
|
|
320
|
+
performMaintenanceAndCleanupSpy.mockRestore();
|
|
321
|
+
randomSpy.mockRestore();
|
|
322
|
+
|
|
323
|
+
// Restore the original localStorage
|
|
324
|
+
Object.defineProperty(window, 'localStorage', {
|
|
325
|
+
value: originalLocalStorage,
|
|
326
|
+
writable: true,
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('should check localStorage for the maintenance timestamp', () => {
|
|
331
|
+
component['performPeriodicMaintenance']();
|
|
332
|
+
expect(mockLocalStorage.getItem).toHaveBeenCalledWith('lastCodingTestStorageMaintenance');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should call performMaintenanceAndCleanup when maintenance was never done', () => {
|
|
336
|
+
mockLocalStorage.getItem.mockReturnValue(null);
|
|
337
|
+
randomSpy.mockReturnValue(0.19);
|
|
338
|
+
|
|
339
|
+
component['performPeriodicMaintenance']();
|
|
340
|
+
|
|
341
|
+
expect(performMaintenanceAndCleanupSpy).toHaveBeenCalled();
|
|
342
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('lastCodingTestStorageMaintenance', expect.any(String));
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should call performMaintenanceAndCleanup when maintenance was done more than a day ago', () => {
|
|
346
|
+
const oneDayInMs = 24 * 60 * 60 * 1000;
|
|
347
|
+
const twoDaysAgo = Date.now() - oneDayInMs * 2;
|
|
348
|
+
mockLocalStorage.getItem.mockReturnValue(twoDaysAgo.toString());
|
|
349
|
+
randomSpy.mockReturnValue(0.19);
|
|
350
|
+
|
|
351
|
+
component['performPeriodicMaintenance']();
|
|
352
|
+
|
|
353
|
+
expect(performMaintenanceAndCleanupSpy).toHaveBeenCalled();
|
|
354
|
+
expect(mockLocalStorage.setItem).toHaveBeenCalledWith('lastCodingTestStorageMaintenance', expect.any(String));
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should not call performMaintenanceAndCleanup when maintenance was done more than a day ago but math random returns more than 0.2', () => {
|
|
358
|
+
const oneDayInMs = 24 * 60 * 60 * 1000;
|
|
359
|
+
const twoDaysAgo = Date.now() - oneDayInMs * 2;
|
|
360
|
+
mockLocalStorage.getItem.mockReturnValue(twoDaysAgo.toString());
|
|
361
|
+
randomSpy.mockReturnValue(0.2);
|
|
362
|
+
|
|
363
|
+
component['performPeriodicMaintenance']();
|
|
364
|
+
|
|
365
|
+
expect(performMaintenanceAndCleanupSpy).not.toHaveBeenCalled();
|
|
366
|
+
expect(mockLocalStorage.setItem).not.toHaveBeenCalled();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('should not call performMaintenanceAndCleanup when maintenance was done recently', () => {
|
|
370
|
+
const recentTime = Date.now() - 1000; // 1 second ago
|
|
371
|
+
mockLocalStorage.getItem.mockReturnValue(recentTime.toString());
|
|
372
|
+
|
|
373
|
+
component['performPeriodicMaintenance']();
|
|
374
|
+
|
|
375
|
+
expect(performMaintenanceAndCleanupSpy).not.toHaveBeenCalled();
|
|
376
|
+
expect(mockLocalStorage.setItem).not.toHaveBeenCalled();
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
describe('when isFullViewMode is false', () => {
|
|
381
|
+
beforeEach(() => {
|
|
382
|
+
component.viewMode = ViewMode.IDEOnly;
|
|
383
|
+
component.ngOnInit();
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('should not set up storage when not in full view mode', () => {
|
|
387
|
+
setupAutoSavedDataSpy.mockReset();
|
|
388
|
+
libCodingTestService.changeCurrentLanguage(component.languages[0].value);
|
|
389
|
+
|
|
390
|
+
component.ngOnInit();
|
|
391
|
+
|
|
392
|
+
expect(setupAutoSavedDataSpy).not.toHaveBeenCalled();
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
describe('when questionId is undefined or null', () => {
|
|
397
|
+
beforeEach(() => {
|
|
398
|
+
setupAutoSavedDataSpy.mockReset();
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should use default-question-id when questionId is undefined', () => {
|
|
402
|
+
component.questionId = undefined;
|
|
403
|
+
|
|
404
|
+
// Create a spy specifically for this test
|
|
405
|
+
const setupSpy = jest.spyOn(storageCodingService, 'setupAutoSavedData');
|
|
406
|
+
|
|
407
|
+
// Run init
|
|
408
|
+
libCodingTestService.changeCurrentLanguage(component.languages[0].value);
|
|
409
|
+
|
|
410
|
+
component.ngOnInit();
|
|
411
|
+
|
|
412
|
+
// Verify the call used the default ID
|
|
413
|
+
expect(setupSpy).toHaveBeenCalledWith(
|
|
414
|
+
component.languages[0].value,
|
|
415
|
+
component.assessmentId,
|
|
416
|
+
'default-question-id',
|
|
417
|
+
true,
|
|
418
|
+
true,
|
|
419
|
+
true,
|
|
420
|
+
'running'
|
|
421
|
+
);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('should use default-question-id when questionId is null', () => {
|
|
425
|
+
component.questionId = null;
|
|
426
|
+
|
|
427
|
+
// Create a spy specifically for this test
|
|
428
|
+
const setupSpy = jest.spyOn(storageCodingService, 'setupAutoSavedData');
|
|
429
|
+
|
|
430
|
+
libCodingTestService.changeCurrentLanguage(component.languages[0].value);
|
|
431
|
+
|
|
432
|
+
// Run init
|
|
433
|
+
component.ngOnInit();
|
|
434
|
+
|
|
435
|
+
// Verify the call used the default ID
|
|
436
|
+
expect(setupSpy).toHaveBeenCalledWith(
|
|
437
|
+
component.languages[0].value,
|
|
438
|
+
component.assessmentId,
|
|
439
|
+
'default-question-id',
|
|
440
|
+
true,
|
|
441
|
+
true,
|
|
442
|
+
true,
|
|
443
|
+
'running'
|
|
444
|
+
);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
describe('when updateTestCases is called', () => {
|
|
449
|
+
let resetLastTestCaseLocalIdSpy: jest.SpyInstance;
|
|
450
|
+
let updateTestCaseLocalIdSpy: jest.SpyInstance;
|
|
451
|
+
let libUpdateTestCasesSpy: jest.SpyInstance;
|
|
452
|
+
let storageUpdateTestCasesSpy: jest.SpyInstance;
|
|
453
|
+
let getSavedTestCasesSpy: jest.SpyInstance;
|
|
454
|
+
|
|
455
|
+
beforeEach(() => {
|
|
456
|
+
updateTestCaseLocalIdSpy = jest.spyOn(TestBed.inject(TestCasesService), 'updateTestCaseLocalId');
|
|
457
|
+
resetLastTestCaseLocalIdSpy = jest.spyOn(TestBed.inject(TestCasesService), 'resetLastTestCaseLocalId');
|
|
458
|
+
libUpdateTestCasesSpy = jest.spyOn(libCodingTestService, 'updateTestCases');
|
|
459
|
+
storageUpdateTestCasesSpy = jest.spyOn(storageCodingService, 'updateTestCases');
|
|
460
|
+
getSavedTestCasesSpy = jest.spyOn(storageCodingService, 'getSavedTestCases');
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('should update test cases when storageTestCasesEnable is true and isLAT is true', () => {
|
|
464
|
+
component.isLAT = true;
|
|
465
|
+
component.mode = Modes.Running;
|
|
466
|
+
|
|
467
|
+
const mockTestCases = [
|
|
468
|
+
{ id: 1, name: 'Test 1', localId: 101, preloaded: true, input: 'input1', expectedOutput: 'output1' },
|
|
469
|
+
{ id: 2, name: 'Test 2', localId: 102, preloaded: false, input: 'input2', expectedOutput: 'output2' },
|
|
470
|
+
];
|
|
471
|
+
|
|
472
|
+
getSavedTestCasesSpy.mockReturnValue(mockTestCases);
|
|
473
|
+
|
|
474
|
+
component.ngOnInit();
|
|
475
|
+
|
|
476
|
+
expect(libUpdateTestCasesSpy).toHaveBeenCalledWith([...mockTestCases]);
|
|
477
|
+
expect(storageUpdateTestCasesSpy).toHaveBeenCalledWith([...mockTestCases]);
|
|
478
|
+
expect(updateTestCaseLocalIdSpy).toHaveBeenCalledWith(102);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('should reset test cases when there are no saved test cases', () => {
|
|
482
|
+
component.isLAT = true;
|
|
483
|
+
component.mode = Modes.Running;
|
|
484
|
+
|
|
485
|
+
getSavedTestCasesSpy.mockReturnValue([]);
|
|
486
|
+
|
|
487
|
+
component.ngOnInit();
|
|
488
|
+
|
|
489
|
+
expect(libUpdateTestCasesSpy).toHaveBeenCalledWith([]);
|
|
490
|
+
expect(storageUpdateTestCasesSpy).toHaveBeenCalledWith([]);
|
|
491
|
+
expect(resetLastTestCaseLocalIdSpy).toHaveBeenCalled();
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
describe('when initCode is changed', () => {
|
|
497
|
+
it('should call necessary setters to reflect initCode changes', () => {
|
|
498
|
+
component.languages = [
|
|
499
|
+
{
|
|
500
|
+
value: CodeEditorLanguages.Java,
|
|
501
|
+
label: 'java',
|
|
502
|
+
},
|
|
503
|
+
];
|
|
504
|
+
libCodingTestService.changeCurrentLanguage(component.languages[0].value);
|
|
505
|
+
const oldInitCode = component.initCode;
|
|
506
|
+
const newInitCode = 'sample java code';
|
|
507
|
+
component.initCode = newInitCode;
|
|
508
|
+
const changes: SimpleChanges = {
|
|
509
|
+
initCode: new SimpleChange(oldInitCode, newInitCode, false),
|
|
510
|
+
};
|
|
511
|
+
component.ngOnChanges(changes);
|
|
512
|
+
|
|
513
|
+
expect(changeLanguageSpy).toBeCalledWith(component.languages[0].value);
|
|
514
|
+
expect(setInitCodeSpy).toBeCalledWith(component.initCode);
|
|
515
|
+
expect(updateInitCodeSpy).toBeCalled();
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
describe('when updateInitCode is called', () => {
|
|
520
|
+
let getSavedCodeSpy: jest.SpyInstance;
|
|
521
|
+
|
|
522
|
+
beforeEach(() => {
|
|
523
|
+
getSavedCodeSpy = jest.spyOn(storageCodingService, 'getSavedCode');
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('should set initCode to savedCode if it exists', () => {
|
|
527
|
+
const savedCode = 'saved code from storage';
|
|
528
|
+
getSavedCodeSpy.mockReturnValue(savedCode);
|
|
529
|
+
|
|
530
|
+
component.updateInitCode('new code');
|
|
531
|
+
|
|
532
|
+
expect(component.initCode).toBe(savedCode);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('should set initCode to provided code if no saved code exists', () => {
|
|
536
|
+
getSavedCodeSpy.mockReturnValue(null);
|
|
537
|
+
const newCode = 'new init code';
|
|
538
|
+
|
|
539
|
+
component.updateInitCode(newCode);
|
|
540
|
+
|
|
541
|
+
expect(component.initCode).toBe(newCode);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
describe('when private methods are tested', () => {
|
|
546
|
+
describe('isSavedLangRelevant method', () => {
|
|
547
|
+
it('should return false when lastLanguageLAT is null or undefined', () => {
|
|
548
|
+
expect(component['isSavedLangRelevant'](null)).toBe(false);
|
|
549
|
+
expect(component['isSavedLangRelevant'](undefined)).toBe(false);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should return true when lastLanguageLAT matches a language value', () => {
|
|
553
|
+
component.languages = [
|
|
554
|
+
{ value: CodeEditorLanguages.Python, label: 'python' },
|
|
555
|
+
{ value: CodeEditorLanguages.Typescript, label: 'typescript' },
|
|
556
|
+
];
|
|
557
|
+
|
|
558
|
+
const lastLang = { value: CodeEditorLanguages.Python, version: '1.0' };
|
|
559
|
+
|
|
560
|
+
expect(component['isSavedLangRelevant'](lastLang)).toBe(true);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
it('should return false when lastLanguageLAT does not match any language value', () => {
|
|
564
|
+
component.languages = [
|
|
565
|
+
{ value: CodeEditorLanguages.Python, label: 'python' },
|
|
566
|
+
{ value: CodeEditorLanguages.Typescript, label: 'typescript' },
|
|
567
|
+
];
|
|
568
|
+
|
|
569
|
+
const lastLang = { value: CodeEditorLanguages.Java, version: '1.0' };
|
|
570
|
+
|
|
571
|
+
expect(component['isSavedLangRelevant'](lastLang)).toBe(false);
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
describe('getRelevantLangVersion method', () => {
|
|
576
|
+
it('should return the version from languages when matching language is found', () => {
|
|
577
|
+
component.languages = [
|
|
578
|
+
{ value: CodeEditorLanguages.Python, label: 'python', version: '3.9' },
|
|
579
|
+
{ value: CodeEditorLanguages.Typescript, label: 'typescript', version: '4.5' },
|
|
580
|
+
];
|
|
581
|
+
|
|
582
|
+
const lastLang = { value: CodeEditorLanguages.Python, version: '3.8' };
|
|
583
|
+
|
|
584
|
+
expect(component['getRelevantLangVersion'](lastLang)).toBe('3.9');
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('should return the version from lastLang when no matching language is found', () => {
|
|
588
|
+
component.languages = [
|
|
589
|
+
{ value: CodeEditorLanguages.Python, label: 'python', version: '3.9' },
|
|
590
|
+
{ value: CodeEditorLanguages.Typescript, label: 'typescript', version: '4.5' },
|
|
591
|
+
];
|
|
592
|
+
|
|
593
|
+
const lastLang = { value: CodeEditorLanguages.Java, version: '11' };
|
|
594
|
+
|
|
595
|
+
expect(component['getRelevantLangVersion'](lastLang)).toBe('11');
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
});
|
|
599
|
+
});
|