@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.
Files changed (163) hide show
  1. package/.eslintrc.json +45 -0
  2. package/README.md +257 -0
  3. package/jest.config.ts +21 -0
  4. package/ng-package.json +14 -0
  5. package/package.json +33 -0
  6. package/project.json +36 -0
  7. package/src/assets/i18n/en.json +124 -0
  8. package/src/index.ts +30 -0
  9. package/src/lib/components/.gitkeep +0 -0
  10. package/src/lib/components/code-editor/code-editor.component.html +10 -0
  11. package/src/lib/components/code-editor/code-editor.component.scss +21 -0
  12. package/src/lib/components/code-editor/code-editor.component.spec.ts +136 -0
  13. package/src/lib/components/code-editor/code-editor.component.ts +369 -0
  14. package/src/lib/components/code-editor/code-editor.mocks.ts +28 -0
  15. package/src/lib/components/code-editor/code-editor.service.spec.ts +160 -0
  16. package/src/lib/components/code-editor/code-editor.service.ts +94 -0
  17. package/src/lib/components/code-editor/helpers/c-helper.spec.ts +39 -0
  18. package/src/lib/components/code-editor/helpers/c-helper.ts +51 -0
  19. package/src/lib/components/code-editor/helpers/code-editor-helper.base.spec.ts +30 -0
  20. package/src/lib/components/code-editor/helpers/code-editor-helper.base.ts +16 -0
  21. package/src/lib/components/code-editor/helpers/code-editor-helper.mocks.ts +24 -0
  22. package/src/lib/components/code-editor/helpers/code-editor-helper.model.ts +67 -0
  23. package/src/lib/components/code-editor/helpers/cpp-helper.spec.ts +40 -0
  24. package/src/lib/components/code-editor/helpers/cpp-helper.ts +52 -0
  25. package/src/lib/components/code-editor/helpers/csharp-helper.spec.ts +42 -0
  26. package/src/lib/components/code-editor/helpers/csharp-helper.ts +55 -0
  27. package/src/lib/components/code-editor/helpers/go-helper.spec.ts +41 -0
  28. package/src/lib/components/code-editor/helpers/go-helper.ts +54 -0
  29. package/src/lib/components/code-editor/helpers/index.ts +15 -0
  30. package/src/lib/components/code-editor/helpers/java-helper.spec.ts +41 -0
  31. package/src/lib/components/code-editor/helpers/java-helper.ts +54 -0
  32. package/src/lib/components/code-editor/helpers/javascript-helper.spec.ts +39 -0
  33. package/src/lib/components/code-editor/helpers/javascript-helper.ts +32 -0
  34. package/src/lib/components/code-editor/helpers/kotlin-helper.spec.ts +41 -0
  35. package/src/lib/components/code-editor/helpers/kotlin-helper.ts +54 -0
  36. package/src/lib/components/code-editor/helpers/php-helper.spec.ts +39 -0
  37. package/src/lib/components/code-editor/helpers/php-helper.ts +32 -0
  38. package/src/lib/components/code-editor/helpers/python-helper.spec.ts +39 -0
  39. package/src/lib/components/code-editor/helpers/python-helper.ts +32 -0
  40. package/src/lib/components/code-editor/helpers/r-helper.spec.ts +39 -0
  41. package/src/lib/components/code-editor/helpers/r-helper.ts +32 -0
  42. package/src/lib/components/code-editor/helpers/ruby-helper.spec.ts +39 -0
  43. package/src/lib/components/code-editor/helpers/ruby-helper.ts +32 -0
  44. package/src/lib/components/code-editor/helpers/scala-helper.spec.ts +41 -0
  45. package/src/lib/components/code-editor/helpers/scala-helper.ts +53 -0
  46. package/src/lib/components/code-editor/helpers/sql-helper.spec.ts +87 -0
  47. package/src/lib/components/code-editor/helpers/sql-helper.ts +44 -0
  48. package/src/lib/components/code-editor/helpers/swift-helper.spec.ts +40 -0
  49. package/src/lib/components/code-editor/helpers/swift-helper.ts +51 -0
  50. package/src/lib/components/code-editor/helpers/typescript-helper.spec.ts +40 -0
  51. package/src/lib/components/code-editor/helpers/typescript-helper.ts +52 -0
  52. package/src/lib/components/code-editor/models/code-editor.model.ts +9 -0
  53. package/src/lib/components/code-editor/models/coding-snapshot.model.ts +4 -0
  54. package/src/lib/components/coding-question/coding-question.component.html +78 -0
  55. package/src/lib/components/coding-question/coding-question.component.scss +76 -0
  56. package/src/lib/components/coding-question/coding-question.component.spec.ts +85 -0
  57. package/src/lib/components/coding-question/coding-question.component.ts +102 -0
  58. package/src/lib/components/coding-section/coding-section.component.html +82 -0
  59. package/src/lib/components/coding-section/coding-section.component.scss +64 -0
  60. package/src/lib/components/coding-section/coding-section.component.spec.ts +257 -0
  61. package/src/lib/components/coding-section/coding-section.component.ts +187 -0
  62. package/src/lib/components/coding-test.module.ts +124 -0
  63. package/src/lib/components/common/truncated-text/truncated-text.component.html +6 -0
  64. package/src/lib/components/common/truncated-text/truncated-text.component.scss +18 -0
  65. package/src/lib/components/common/truncated-text/truncated-text.component.spec.ts +84 -0
  66. package/src/lib/components/common/truncated-text/truncated-text.component.ts +37 -0
  67. package/src/lib/components/configurations/configurations.component.html +57 -0
  68. package/src/lib/components/configurations/configurations.component.scss +42 -0
  69. package/src/lib/components/configurations/configurations.component.spec.ts +186 -0
  70. package/src/lib/components/configurations/configurations.component.ts +98 -0
  71. package/src/lib/components/instructions/instructions.component.html +41 -0
  72. package/src/lib/components/instructions/instructions.component.scss +167 -0
  73. package/src/lib/components/instructions/instructions.component.spec.ts +106 -0
  74. package/src/lib/components/instructions/instructions.component.ts +138 -0
  75. package/src/lib/components/panel/panel.component.html +19 -0
  76. package/src/lib/components/panel/panel.component.scss +41 -0
  77. package/src/lib/components/panel/panel.component.spec.ts +40 -0
  78. package/src/lib/components/panel/panel.component.ts +34 -0
  79. package/src/lib/components/runnable-editor/runnable-editor.component.html +75 -0
  80. package/src/lib/components/runnable-editor/runnable-editor.component.scss +55 -0
  81. package/src/lib/components/runnable-editor/runnable-editor.component.spec.ts +124 -0
  82. package/src/lib/components/runnable-editor/runnable-editor.component.ts +155 -0
  83. package/src/lib/components/tests/test-cases/test-cases.component.html +135 -0
  84. package/src/lib/components/tests/test-cases/test-cases.component.scss +220 -0
  85. package/src/lib/components/tests/test-cases/test-cases.component.spec.ts +401 -0
  86. package/src/lib/components/tests/test-cases/test-cases.component.ts +205 -0
  87. package/src/lib/components/tests/test-cases-content/test-cases-content.component.html +94 -0
  88. package/src/lib/components/tests/test-cases-content/test-cases-content.component.scss +103 -0
  89. package/src/lib/components/tests/test-cases-content/test-cases-content.component.spec.ts +122 -0
  90. package/src/lib/components/tests/test-cases-content/test-cases-content.component.ts +102 -0
  91. package/src/lib/components/tests/test-cases-status/test-cases-status.component.html +16 -0
  92. package/src/lib/components/tests/test-cases-status/test-cases-status.component.scss +49 -0
  93. package/src/lib/components/tests/test-cases-status/test-cases-status.component.spec.ts +22 -0
  94. package/src/lib/components/tests/test-cases-status/test-cases-status.component.ts +18 -0
  95. package/src/lib/components/tests/test-results.component.html +119 -0
  96. package/src/lib/components/tests/test-results.component.scss +189 -0
  97. package/src/lib/components/tests/test-results.component.spec.ts +140 -0
  98. package/src/lib/components/tests/test-results.component.ts +98 -0
  99. package/src/lib/components/tgo-coding-test/tgo-coding-test.component.html +96 -0
  100. package/src/lib/components/tgo-coding-test/tgo-coding-test.component.scss +6 -0
  101. package/src/lib/components/tgo-coding-test/tgo-coding-test.component.spec.ts +599 -0
  102. package/src/lib/components/tgo-coding-test/tgo-coding-test.component.ts +279 -0
  103. package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.html +36 -0
  104. package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.scss +183 -0
  105. package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.spec.ts +883 -0
  106. package/src/lib/components/tgo-coding-test-candidate-view/tgo-coding-test-candidate-view.component.ts +575 -0
  107. package/src/lib/config/index.ts +3 -0
  108. package/src/lib/config/tgo-coding-test.config.ts +26 -0
  109. package/src/lib/config/tgo-coding-test.provider.ts +38 -0
  110. package/src/lib/config/tgo-coding-test.token.ts +21 -0
  111. package/src/lib/models/.gitkeep +0 -0
  112. package/src/lib/models/auto-saved-data.ts +51 -0
  113. package/src/lib/models/code-event.ts +17 -0
  114. package/src/lib/models/coderunner-execution-results.ts +58 -0
  115. package/src/lib/models/coding-lib.mocks.ts +246 -0
  116. package/src/lib/models/configs.ts +18 -0
  117. package/src/lib/models/language-change-action.ts +4 -0
  118. package/src/lib/models/lat-languages.ts +12 -0
  119. package/src/lib/models/mixpanel-events.ts +3 -0
  120. package/src/lib/models/mode.ts +5 -0
  121. package/src/lib/models/paste-data.ts +4 -0
  122. package/src/lib/models/programming-language.ts +9 -0
  123. package/src/lib/models/test-cases.ts +74 -0
  124. package/src/lib/models/theme.ts +5 -0
  125. package/src/lib/models/translations.ts +1 -0
  126. package/src/lib/models/view-mode.ts +6 -0
  127. package/src/lib/pipes/memoize-func.pipe.ts +34 -0
  128. package/src/lib/services/.gitkeep +0 -0
  129. package/src/lib/services/candidate-coding-test-services/candidature-api.service.spec.ts +40 -0
  130. package/src/lib/services/candidate-coding-test-services/candidature-api.service.ts +15 -0
  131. package/src/lib/services/candidate-coding-test-services/coderunner-api.service.spec.ts +134 -0
  132. package/src/lib/services/candidate-coding-test-services/coderunner-api.service.ts +105 -0
  133. package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.spec.ts +161 -0
  134. package/src/lib/services/candidate-coding-test-services/coding-test-tour.service.ts +100 -0
  135. package/src/lib/services/candidate-coding-test-services/coding-test.service.spec.ts +1524 -0
  136. package/src/lib/services/candidate-coding-test-services/coding-test.service.ts +843 -0
  137. package/src/lib/services/candidate-coding-test-services/index.ts +4 -0
  138. package/src/lib/services/coding-test-config.service.ts +48 -0
  139. package/src/lib/services/configurations.service.mocks.ts +77 -0
  140. package/src/lib/services/configurations.service.spec.ts +79 -0
  141. package/src/lib/services/configurations.service.ts +111 -0
  142. package/src/lib/services/index.ts +0 -0
  143. package/src/lib/services/lib-coding-test.service.spec.ts +265 -0
  144. package/src/lib/services/lib-coding-test.service.ts +157 -0
  145. package/src/lib/services/local-storage.service.mocks.ts +22 -0
  146. package/src/lib/services/storage.service.spec.ts +1120 -0
  147. package/src/lib/services/storage.service.ts +729 -0
  148. package/src/lib/services/test-cases.service.spec.ts +53 -0
  149. package/src/lib/services/test-cases.service.ts +29 -0
  150. package/src/lib/services/theme.service.spec.ts +76 -0
  151. package/src/lib/services/theme.service.ts +34 -0
  152. package/src/lib/styles/mixins.scss +86 -0
  153. package/src/lib/styles/styles.scss +112 -0
  154. package/src/lib/styles/variables.scss +105 -0
  155. package/src/lib/utils/.gitkeep +0 -0
  156. package/src/lib/utils/additional-languages/erlang.ts +115 -0
  157. package/src/lib/utils/resize-element.ts +15 -0
  158. package/src/lib/utils/time-to-ms.util.ts +10 -0
  159. package/src/test-setup.ts +1 -0
  160. package/tsconfig.json +16 -0
  161. package/tsconfig.lib.json +12 -0
  162. package/tsconfig.lib.prod.json +9 -0
  163. package/tsconfig.spec.json +13 -0
@@ -0,0 +1,1524 @@
1
+ import { fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
2
+ import {
3
+ ConfirmDialogComponent,
4
+ DialogComponentModule,
5
+ DialogService,
6
+ SnackbarService,
7
+ } from '@testgorilla/tgo-ui';
8
+ import {
9
+ getTranslocoModule,
10
+ MixpanelService,
11
+ TestResultRead,
12
+ } from '@testgorilla/tgo-test-shared';
13
+ import { asyncScheduler, Observable, of, scheduled, Subject } from 'rxjs';
14
+
15
+ import { MatDialogRef } from '@angular/material/dialog';
16
+ import { CodingTestsResultsModel } from '../../models/coderunner-execution-results';
17
+ import { ProgrammingLanguageVersioned } from '../../models/programming-language';
18
+ import { SqlTestCase } from '../../models/test-cases';
19
+ import { LibCodingTestService } from '../lib-coding-test.service';
20
+ import { ResetCodeAction } from '../lib-coding-test.service';
21
+ import { TestCaseDeletionAction } from '../../models/test-cases';
22
+ import { TestCaseDeletionData } from '../../models/test-cases';
23
+ import { CoderunnerApiService } from './coderunner-api.service';
24
+ import { CodingTestService } from './coding-test.service';
25
+
26
+ class MixpanelServiceMock {
27
+ track = jest.fn();
28
+ }
29
+
30
+ describe('CodingTestService', () => {
31
+ let service: CodingTestService;
32
+ let libCodingTestService: LibCodingTestService;
33
+ let coderunnerApiService: CoderunnerApiService;
34
+ let mixpanelService: MixpanelService;
35
+ let dialogSpy: jest.SpyInstance;
36
+ const companyColor = '#D410AA';
37
+ const afterClosedResult = of(true);
38
+ const afterClosedResultCancel = of(false);
39
+ const dialogRefSpy = {
40
+ afterClosed: jest.fn(() => afterClosedResult),
41
+ } as unknown as MatDialogRef<unknown>;
42
+ const dialogRefSpyCancel = {
43
+ afterClosed: jest.fn(() => afterClosedResultCancel),
44
+ } as unknown as MatDialogRef<unknown>;
45
+ let confirmResetSpy: jest.SpyInstance;
46
+ const LATlanguage = 'python';
47
+ const LATversion = '3.10.0';
48
+ const fullProgrammingLang = {
49
+ id: 1,
50
+ name: LATlanguage,
51
+ version: LATversion,
52
+ };
53
+ const defaultProgrammingLang = {
54
+ id: 2,
55
+ name: 'javascript',
56
+ version: '1.2.3',
57
+ };
58
+ const testCaseDeletionSubj$ = new Subject<TestCaseDeletionData>();
59
+ const libCodingTestServiceMock = {
60
+ confirmReset: jest.fn(),
61
+ codeReset$: scheduled(of(ResetCodeAction.Try), asyncScheduler),
62
+ configFieldChanged$: of(null),
63
+ currentLanguage$: of(LATlanguage),
64
+ getVersion: jest.fn(() => LATversion),
65
+ getValidTestCases: jest.fn(() => [
66
+ {
67
+ id: 1,
68
+ name: 'Example 1',
69
+ input: '1\n2\n2',
70
+ expectedOutput: '0 1 0',
71
+ preloaded: true,
72
+ },
73
+ {
74
+ name: 'Test 1',
75
+ input: '1\n2\n3',
76
+ expectedOutput: '0 1 1',
77
+ preloaded: true,
78
+ },
79
+ {
80
+ name: 'Custom 1',
81
+ input: 'Custom 1',
82
+ expectedOutput: '0 1 0',
83
+ preloaded: false,
84
+ },
85
+ {
86
+ name: 'Custom 2',
87
+ input: 'Custom 2',
88
+ expectedOutput: '0 1 1',
89
+ preloaded: false,
90
+ },
91
+ ]),
92
+ getTestCasesCount: jest.fn(() => 6),
93
+ confirmLanguageChange: jest.fn(),
94
+ cancelLanguageChange: jest.fn(),
95
+ testCaseDeletion$: testCaseDeletionSubj$.asObservable(),
96
+ confirmTestCaseDeletion: jest.fn(),
97
+ };
98
+ let runTestResponse: Record<string, unknown> = {};
99
+ let LATResultsValue: CodingTestsResultsModel;
100
+ let SQLResultsValue: CodingTestsResultsModel;
101
+ const resultId = 1;
102
+ const testResultId = 1;
103
+ const id = 123;
104
+ const code = 'lorem';
105
+ const executedSuccessfullyCopyPath =
106
+ 'CODING_QUESTION.CODING_LIB.TEST_RESULTS.TEST_CASES.EXECUTED_SUCCESSFULLY';
107
+ const sqlexecutedSuccessfullyCopyPath =
108
+ 'CODING_QUESTION.CODING_LIB.TEST_RESULTS.TEST_CASES.SQL_EXECUTED_SUCCESSFULLY';
109
+ const noneOutputCopyPath =
110
+ 'CODING_QUESTION.CODING_LIB.TEST_RESULTS.TEST_CASES.NONE';
111
+ const noResponseOutputCopyPath =
112
+ 'CODING_QUESTION.CODING_LIB.TEST_RESULTS.TEST_CASES.NO_RESPONSE';
113
+ const timeoutErrorCopyPath =
114
+ 'CODING_QUESTION.CODING_LIB.TEST_RESULTS.TEST_CASES.TIMEOUT_ERROR';
115
+
116
+ jest.mock('@ngneat/transloco', () => ({
117
+ translate: (key: string) => key,
118
+ }));
119
+
120
+ beforeEach(() => {
121
+ TestBed.configureTestingModule({
122
+ imports: [DialogComponentModule, getTranslocoModule()],
123
+ providers: [
124
+ CodingTestService,
125
+ {
126
+ provide: LibCodingTestService,
127
+ useValue: libCodingTestServiceMock,
128
+ },
129
+ {
130
+ provide: CoderunnerApiService,
131
+ useValue: {
132
+ runPublicTest$: jest.fn().mockReturnValue(of(runTestResponse)),
133
+ runPreviewTest$: jest.fn().mockReturnValue(of(runTestResponse)),
134
+ runNonPreviewTest$: jest.fn().mockReturnValue(of(runTestResponse)),
135
+ sendCodeEvent$: jest.fn().mockReturnValue(of({})),
136
+ },
137
+ },
138
+ {
139
+ provide: SnackbarService,
140
+ useValue: {
141
+ open: jest.fn(),
142
+ },
143
+ },
144
+ {
145
+ provide: MixpanelService,
146
+ useClass: MixpanelServiceMock,
147
+ },
148
+ ],
149
+ });
150
+ });
151
+
152
+ beforeEach(() => {
153
+ service = TestBed.inject(CodingTestService);
154
+ libCodingTestService = TestBed.inject(LibCodingTestService);
155
+ coderunnerApiService = TestBed.inject(CoderunnerApiService);
156
+ mixpanelService = TestBed.inject(MixpanelService);
157
+
158
+ confirmResetSpy = jest.spyOn(libCodingTestService, 'confirmReset');
159
+ runTestResponse = {};
160
+ service.setCurrentLanguageLAT(defaultProgrammingLang);
161
+ });
162
+
163
+ describe('when transformToExampleLATtestCase is called', () => {
164
+ it('should return example test case', () => {
165
+ const testCase = {
166
+ id: 1,
167
+ input: 'Custom 1',
168
+ name: '',
169
+ solution: '0 1 0',
170
+ };
171
+ const exampleTestCase = service.transformToExampleLATtestCase(
172
+ testCase,
173
+ 0
174
+ );
175
+ const expectedTestCase = {
176
+ id: 1,
177
+ name: 'Example 1',
178
+ input: 'Custom 1',
179
+ expectedOutput: '0 1 0',
180
+ preloaded: true,
181
+ };
182
+
183
+ expect(exampleTestCase).toEqual(expectedTestCase);
184
+ });
185
+ });
186
+
187
+ describe('when setSqlTestCases is called', () => {
188
+ it('should set sqlTestCases', () => {
189
+ const testCase = {
190
+ id: 1,
191
+ name: '',
192
+ category: 'user',
193
+ };
194
+ service.setSqlTestCases([testCase as SqlTestCase]);
195
+
196
+ expect(service.getSqlTestCases()).toContain(testCase);
197
+ });
198
+ });
199
+
200
+ describe('when handler for reset code modal is called', () => {
201
+ const context = 'CODING_QUESTION.MODALS.RESET_CODE.';
202
+ const modalData = {
203
+ confirmButtonText: `${context}SUBMIT`,
204
+ message: `${context}MESSAGE`,
205
+ title: `${context}TITLE`,
206
+ color: companyColor,
207
+ };
208
+ const applicationTheme = 'dark';
209
+ const modalSize = 'small';
210
+
211
+ beforeEach(() => {
212
+ dialogSpy = jest
213
+ .spyOn(TestBed.inject(DialogService), 'open')
214
+ .mockReturnValue(dialogRefSpy);
215
+ });
216
+
217
+ it('should open Dialog', () => {
218
+ service.handleResetCodeModal(applicationTheme, companyColor);
219
+ expect(dialogSpy).toHaveBeenCalledWith(ConfirmDialogComponent, {
220
+ applicationTheme: applicationTheme,
221
+ size: modalSize,
222
+ extraData: modalData,
223
+ });
224
+ });
225
+
226
+ it('should call confirm reset if modal is closed with confirmation', () => {
227
+ service.handleResetCodeModal(applicationTheme, companyColor);
228
+ expect(dialogRefSpy.afterClosed).toHaveBeenCalled();
229
+ expect(confirmResetSpy).toHaveBeenCalled();
230
+ });
231
+ });
232
+
233
+ describe('when listenDeleteCustomTestCases is called', () => {
234
+ it('should return testCaseDeletion$ observable with only Try action', (done) => {
235
+ service.listenDeleteCustomTestCases().subscribe(({ action }) => {
236
+ expect(action).toBe(TestCaseDeletionAction.Try);
237
+ done();
238
+ });
239
+
240
+ testCaseDeletionSubj$.next({
241
+ action: TestCaseDeletionAction.Try,
242
+ index: 1,
243
+ });
244
+ });
245
+ });
246
+
247
+ describe('when handleDeleteTestCaseModal is called', () => {
248
+ const context = 'CODING_QUESTION.MODALS.DELETE_TEST_CASE.';
249
+ const modalData = {
250
+ confirmButtonText: `${context}SUBMIT`,
251
+ message: `${context}MESSAGE`,
252
+ title: `${context}TITLE`,
253
+ color: companyColor,
254
+ };
255
+
256
+ let confirmTestCaseDeletionSpy: jest.SpyInstance;
257
+ const applicationTheme = 'dark';
258
+ const modalSize = 'small';
259
+
260
+ beforeEach(() => {
261
+ dialogSpy = jest
262
+ .spyOn(TestBed.inject(DialogService), 'open')
263
+ .mockReturnValue(dialogRefSpy);
264
+ confirmTestCaseDeletionSpy = jest.spyOn(
265
+ libCodingTestService,
266
+ 'confirmTestCaseDeletion'
267
+ );
268
+ });
269
+
270
+ afterEach(() => {
271
+ jest.clearAllMocks();
272
+ });
273
+
274
+ it('should open Dialog', () => {
275
+ const index = 3;
276
+
277
+ service.handleDeleteTestCaseModal(index, applicationTheme, companyColor);
278
+
279
+ expect(dialogSpy).toHaveBeenCalledWith(ConfirmDialogComponent, {
280
+ applicationTheme: applicationTheme,
281
+ size: modalSize,
282
+ extraData: modalData,
283
+ });
284
+ });
285
+
286
+ it('should call confirmTestCaseDeletion if modal is closed with confirmation', () => {
287
+ const index = 3;
288
+
289
+ service.handleDeleteTestCaseModal(index, applicationTheme, companyColor);
290
+
291
+ expect(dialogRefSpy.afterClosed).toHaveBeenCalled();
292
+ expect(confirmTestCaseDeletionSpy).toHaveBeenCalled();
293
+ });
294
+
295
+ it('should call cancelLanguageChange if modal is closed with cancellation', () => {
296
+ const index = 3;
297
+ dialogSpy = jest
298
+ .spyOn(TestBed.inject(DialogService), 'open')
299
+ .mockReturnValue(dialogRefSpyCancel);
300
+
301
+ service.handleDeleteTestCaseModal(index, applicationTheme, companyColor);
302
+
303
+ expect(dialogRefSpyCancel.afterClosed).toHaveBeenCalled();
304
+ expect(confirmTestCaseDeletionSpy).not.toHaveBeenCalled();
305
+ });
306
+ });
307
+
308
+ describe('when handler for language change modal is called', () => {
309
+ const context = 'CODING_QUESTION.MODALS.LANGUAGE_CHANGE.';
310
+ const modalData = {
311
+ confirmButtonText: `${context}SUBMIT`,
312
+ message: `${context}MESSAGE`,
313
+ title: `${context}TITLE`,
314
+ };
315
+ const defaultApplicationTheme = 'light';
316
+ const modalSize = 'small';
317
+
318
+ let confirmLanguageChangeSpy: jest.SpyInstance;
319
+ let cancelLanguageChangeSpy: jest.SpyInstance;
320
+
321
+ beforeEach(() => {
322
+ confirmLanguageChangeSpy = jest.spyOn(
323
+ libCodingTestService,
324
+ 'confirmLanguageChange'
325
+ );
326
+ cancelLanguageChangeSpy = jest.spyOn(
327
+ libCodingTestService,
328
+ 'cancelLanguageChange'
329
+ );
330
+ });
331
+
332
+ afterEach(() => {
333
+ jest.clearAllMocks();
334
+ });
335
+
336
+ it('should open Dialog', () => {
337
+ dialogSpy = jest
338
+ .spyOn(TestBed.inject(DialogService), 'open')
339
+ .mockReturnValue(dialogRefSpy);
340
+ service.handleLanguageChangeModal(0);
341
+ expect(dialogSpy).toHaveBeenCalledWith(ConfirmDialogComponent, {
342
+ applicationTheme: defaultApplicationTheme,
343
+ size: modalSize,
344
+ extraData: modalData,
345
+ });
346
+ });
347
+
348
+ it('should call confirmLanguageChange if modal is closed with confirmation', () => {
349
+ dialogSpy = jest
350
+ .spyOn(TestBed.inject(DialogService), 'open')
351
+ .mockReturnValue(dialogRefSpy);
352
+ service.handleLanguageChangeModal(0);
353
+ expect(dialogRefSpy.afterClosed).toHaveBeenCalled();
354
+ expect(confirmLanguageChangeSpy).toHaveBeenCalled();
355
+ expect(cancelLanguageChangeSpy).not.toHaveBeenCalled();
356
+ });
357
+
358
+ it('should call cancelLanguageChange if modal is closed with cancellation', () => {
359
+ dialogSpy = jest
360
+ .spyOn(TestBed.inject(DialogService), 'open')
361
+ .mockReturnValue(dialogRefSpyCancel);
362
+ service.handleLanguageChangeModal(0);
363
+ expect(dialogRefSpyCancel.afterClosed).toHaveBeenCalled();
364
+ expect(confirmLanguageChangeSpy).not.toHaveBeenCalled();
365
+ expect(cancelLanguageChangeSpy).toHaveBeenCalled();
366
+ });
367
+
368
+ describe('and selectedLanguage is passed', () => {
369
+ it('should call setCurrentLanguageLAT with passed language', () => {
370
+ const setLangSpy = jest.spyOn(service, 'setCurrentLanguageLAT');
371
+ dialogSpy = jest
372
+ .spyOn(TestBed.inject(DialogService), 'open')
373
+ .mockReturnValue(dialogRefSpy);
374
+ service.handleLanguageChangeModal(0, fullProgrammingLang);
375
+ expect(confirmLanguageChangeSpy).toHaveBeenCalled();
376
+ expect(setLangSpy).toHaveBeenCalledWith(fullProgrammingLang);
377
+ });
378
+ });
379
+ });
380
+
381
+ describe('when setCurrentLanguageLAT is called', () => {
382
+ it('should set current language', () => {
383
+ service.setCurrentLanguageLAT(fullProgrammingLang);
384
+ expect(service['currentLanguage']).toEqual(fullProgrammingLang);
385
+ });
386
+ });
387
+
388
+ describe('when listener for coding changes is called', () => {
389
+ it('should return an observable with ResetCodeAction.Try', (done) => {
390
+ service.listenCodingTestChanges().subscribe((value) => {
391
+ expect(value).toEqual(ResetCodeAction.Try);
392
+ done();
393
+ });
394
+ });
395
+ });
396
+
397
+ describe('when runTest() is called', () => {
398
+ it('should set loading results to true', () => {
399
+ service.runTest(resultId, 'lorem', false);
400
+
401
+ expect(service.isTestResultsLoading()).toBeTruthy();
402
+ });
403
+
404
+ it('should reset summary', fakeAsync(() => {
405
+ const spy = jest.spyOn(service, 'resetRunTestSummary');
406
+
407
+ service.runTest(resultId, code, false);
408
+ tick();
409
+
410
+ expect(spy).toHaveBeenCalled();
411
+ flush();
412
+ }));
413
+
414
+ describe('and isSQL === true', () => {
415
+ const attemptId = '12345';
416
+ let runTestData;
417
+ const sqlTestCases: SqlTestCase[] = [
418
+ {
419
+ id: 1,
420
+ name: 'Passing Test',
421
+ category: 'user',
422
+ initial_sql:
423
+ 'CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT);',
424
+ pre_sql: "INSERT INTO test_table VALUES (1, 'Hello'), (2, 'World');",
425
+ post_sql: '',
426
+ result: "'Hello', 'World'",
427
+ },
428
+ {
429
+ id: 2,
430
+ name: 'Failing Test',
431
+ category: 'user',
432
+ initial_sql:
433
+ 'CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT);',
434
+ pre_sql: "INSERT INTO test_table VALUES (1, 'Hello'), (2, 'World');",
435
+ post_sql: 'SELECT * FROM',
436
+ result: "'Goodbye', 'Everyone'",
437
+ },
438
+ ];
439
+ beforeEach(() => {
440
+ service.setSqlTestCases(sqlTestCases);
441
+ runTestResponse = {
442
+ id: attemptId,
443
+ executions: [
444
+ {
445
+ input: '',
446
+ evaluation: {
447
+ testcase: true,
448
+ score: 100,
449
+ },
450
+ run: {
451
+ stdout: "'Hello', 'World'",
452
+ stderr: null,
453
+ output: "'Hello', 'World'",
454
+ signal: null,
455
+ code: 0,
456
+ },
457
+ compile: null,
458
+ attempt_id: 'attempt-passing-123',
459
+ submission_id: 'submission-passing-123',
460
+ validation_id: null,
461
+ id: 'exec-passing-123',
462
+ created_at: '2024-03-01T12:00:00.000Z',
463
+ updated_at: '2024-03-01T12:00:00.000Z',
464
+ },
465
+ {
466
+ input: '',
467
+ evaluation: {
468
+ testcase: false,
469
+ score: 0,
470
+ },
471
+ run: {
472
+ stdout: "'Hello', 'World'",
473
+ stderr: "Expected: 'Goodbye', 'Everyone'",
474
+ output: "'Hello', 'World'",
475
+ signal: null,
476
+ code: 1,
477
+ },
478
+ compile: null,
479
+ attempt_id: 'attempt-failing-123',
480
+ submission_id: 'submission-failing-123',
481
+ validation_id: null,
482
+ id: 'exec-failing-123',
483
+ created_at: '2024-03-01T12:05:00.000Z',
484
+ updated_at: '2024-03-01T12:05:00.000Z',
485
+ },
486
+ ],
487
+ };
488
+ SQLResultsValue = {
489
+ resume: { ok: 1, error: 1, total: 2 },
490
+ listResponse: [
491
+ {
492
+ actualOutput: "'Hello', 'World'",
493
+ logs: sqlexecutedSuccessfullyCopyPath,
494
+ status: 'passed',
495
+ },
496
+ {
497
+ actualOutput: "'Hello', 'World'",
498
+ logs: "Expected: 'Goodbye', 'Everyone'\n",
499
+ status: 'error',
500
+ },
501
+ ],
502
+ };
503
+ });
504
+
505
+ it('should call setSqlTestCases and getSqlTestCases', () => {
506
+ const retrievedTestCases = service.getSqlTestCases();
507
+ expect(retrievedTestCases).toEqual(sqlTestCases);
508
+ });
509
+
510
+ describe('and publicPreview === true', () => {
511
+ it('should call coderunnerApiService runPublicTest$', fakeAsync(() => {
512
+ runTestData = {
513
+ code: 'SELECT value FROM test_table;',
514
+ };
515
+ const runCodeSpy = jest.spyOn(coderunnerApiService, 'runPublicTest$');
516
+
517
+ service.runTest(
518
+ resultId,
519
+ runTestData.code as string,
520
+ false,
521
+ true,
522
+ true
523
+ );
524
+
525
+ tick();
526
+ expect(runCodeSpy).toHaveBeenCalledWith(
527
+ runTestData.code,
528
+ service.getSqlTestCases(),
529
+ ProgrammingLanguageVersioned.SQLite
530
+ );
531
+ }));
532
+ it('should emit isLoading false', fakeAsync(() => {
533
+ service.runTest(resultId, code, false, true, true, false, id, 0);
534
+ tick();
535
+ expect(service.isTestResultsLoading()).toBeFalsy();
536
+
537
+ flush();
538
+ }));
539
+
540
+ it('should emit returned value to codingTestResults$', fakeAsync(() => {
541
+ service.runTest(resultId, code, false, true, true, false, id, 0);
542
+ tick();
543
+
544
+ service.codingTestResults$.subscribe((val) => {
545
+ expect(val).toEqual(SQLResultsValue);
546
+ });
547
+
548
+ flush();
549
+ }));
550
+ });
551
+
552
+ describe('and publicPreview === false and preview === true', () => {
553
+ it('should call coderunnerApiService runPreviewTest$', fakeAsync(() => {
554
+ runTestData = {
555
+ code: 'SELECT value FROM test_table;',
556
+ };
557
+
558
+ const runCodeSpy = jest.spyOn(
559
+ coderunnerApiService,
560
+ 'runPreviewTest$'
561
+ );
562
+
563
+ service.runTest(
564
+ resultId,
565
+ runTestData.code,
566
+ false,
567
+ true,
568
+ false,
569
+ true,
570
+ id,
571
+ testResultId
572
+ );
573
+
574
+ tick();
575
+ expect(runCodeSpy).toHaveBeenCalledWith(
576
+ testResultId,
577
+ runTestData.code,
578
+ service.getSqlTestCases(),
579
+ ProgrammingLanguageVersioned.SQLite
580
+ );
581
+ }));
582
+ it('should emit isLoading false', fakeAsync(() => {
583
+ service.runTest(resultId, code, false, true, false, true, id, 0);
584
+ tick();
585
+ expect(service.isTestResultsLoading()).toBeFalsy();
586
+
587
+ flush();
588
+ }));
589
+
590
+ it('should emit returned value to codingTestResults$', fakeAsync(() => {
591
+ service.runTest(resultId, code, false, true, false, true, id, 0);
592
+ tick();
593
+
594
+ service.codingTestResults$.subscribe((val) => {
595
+ expect(val).toEqual(SQLResultsValue);
596
+ });
597
+
598
+ flush();
599
+ }));
600
+ });
601
+ describe('and publicPreview === false and preview === false', () => {
602
+ it('should call candidatureApiService sendCodeEvent$', fakeAsync(() => {
603
+ jest
604
+ .spyOn(coderunnerApiService, 'runNonPreviewTest$')
605
+ .mockReturnValue(of(runTestResponse));
606
+ runTestData = {
607
+ code: 'SELECT value FROM test_table;',
608
+ };
609
+ const sendEventSpy = jest.spyOn(
610
+ coderunnerApiService,
611
+ 'sendCodeEvent$'
612
+ );
613
+ const event = {
614
+ event_type: 'ATTEMPT',
615
+ attempt_id: attemptId,
616
+ extra_payload: '',
617
+ question_result_id: resultId,
618
+ code: runTestData.code,
619
+ language: `${service['currentLanguage'].name}-${service['currentLanguage'].version}`,
620
+ };
621
+
622
+ service.runTest(
623
+ resultId,
624
+ runTestData.code,
625
+ false,
626
+ true,
627
+ false,
628
+ false,
629
+ id
630
+ );
631
+
632
+ tick();
633
+ expect(sendEventSpy).toHaveBeenCalledWith(event);
634
+ }));
635
+ it('should call coderunnerApiService runNonPreviewTest$', fakeAsync(() => {
636
+ runTestData = {
637
+ code: 'SELECT value FROM test_table;',
638
+ };
639
+ const runCodeSpy = jest.spyOn(
640
+ coderunnerApiService,
641
+ 'runNonPreviewTest$'
642
+ );
643
+
644
+ service.runTest(
645
+ resultId,
646
+ runTestData.code,
647
+ false,
648
+ true,
649
+ false,
650
+ false,
651
+ id
652
+ );
653
+
654
+ tick();
655
+ expect(runCodeSpy).toHaveBeenCalledWith(
656
+ id,
657
+ resultId,
658
+ runTestData.code,
659
+ service.getSqlTestCases(),
660
+ ProgrammingLanguageVersioned.SQLite
661
+ );
662
+ }));
663
+ it('should emit isLoading false', fakeAsync(() => {
664
+ service.runTest(resultId, code, false, true, false, false, id, 0);
665
+ tick();
666
+ expect(service.isTestResultsLoading()).toBeFalsy();
667
+
668
+ flush();
669
+ }));
670
+
671
+ it('should emit returned value to codingTestResults$', fakeAsync(() => {
672
+ service.runTest(resultId, code, false, true, false, false, id, 0);
673
+ tick();
674
+
675
+ service.codingTestResults$.subscribe((val) => {
676
+ expect(val).toEqual(SQLResultsValue);
677
+ });
678
+
679
+ flush();
680
+ }));
681
+ });
682
+ });
683
+
684
+ describe('and isLAT === true', () => {
685
+ let testUuidRaw: string;
686
+ let testUuidTransformed: string;
687
+ let testName: string;
688
+ let testData: TestResultRead;
689
+ let mixpanelSpy: jest.SpyInstance;
690
+ const mixpanelTestCasesEvent = 'Candidate ran tests in Coderunner';
691
+ const attemptId = '45677';
692
+
693
+ beforeEach(() => {
694
+ testUuidRaw = 'some-test-uuid';
695
+ testUuidTransformed = 'sometestuuid';
696
+ testName = 'coding lat entry level';
697
+ testData = {
698
+ is_preview_mode: true,
699
+ uuid: testUuidRaw,
700
+ test: { name: testName },
701
+ } as TestResultRead;
702
+ mixpanelSpy = jest.spyOn(mixpanelService, 'track');
703
+ });
704
+
705
+ describe('and publicPreview === true', () => {
706
+ beforeEach(() => {
707
+ runTestResponse = {
708
+ id: attemptId,
709
+ executions: [
710
+ {
711
+ input: '1\n2\n2',
712
+ evaluation: {
713
+ score: 0,
714
+ testcase: true,
715
+ },
716
+ run: {
717
+ stdout: '0 1 0\n',
718
+ stderr: null,
719
+ output: '0 1 0\n',
720
+ signal: null,
721
+ code: null,
722
+ },
723
+ compile: null,
724
+ },
725
+ {
726
+ input: '1\n2\n3',
727
+ evaluation: {
728
+ score: 0,
729
+ testcase: false,
730
+ },
731
+ run: {
732
+ stdout: '0 0 1\n',
733
+ stderr: null,
734
+ output: '0 0 1\n',
735
+ signal: null,
736
+ code: null,
737
+ },
738
+ compile: null,
739
+ },
740
+ {
741
+ input: 'Custom 1',
742
+ evaluation: {
743
+ score: 0,
744
+ testcase: true,
745
+ },
746
+ run: {
747
+ stdout: '0 1 0\n',
748
+ stderr: null,
749
+ output: '0 1 0\n',
750
+ signal: null,
751
+ code: null,
752
+ },
753
+ compile: null,
754
+ },
755
+ {
756
+ input: 'Custom 2',
757
+ evaluation: {
758
+ score: 0,
759
+ testcase: false,
760
+ },
761
+ run: {
762
+ stdout: '0 0 1\n',
763
+ stderr: null,
764
+ output: '0 0 1\n',
765
+ signal: null,
766
+ code: null,
767
+ },
768
+ compile: null,
769
+ },
770
+ ],
771
+ };
772
+ LATResultsValue = {
773
+ resume: { ok: 2, error: 2, total: 4 },
774
+ listResponse: [
775
+ {
776
+ actualOutput: '0 1 0\n',
777
+ logs: executedSuccessfullyCopyPath,
778
+ status: 'passed',
779
+ },
780
+ {
781
+ actualOutput: '0 0 1\n',
782
+ logs: executedSuccessfullyCopyPath,
783
+ status: 'error',
784
+ },
785
+ {
786
+ actualOutput: '0 1 0\n',
787
+ logs: executedSuccessfullyCopyPath,
788
+ status: 'passed',
789
+ },
790
+ {
791
+ actualOutput: '0 0 1\n',
792
+ logs: executedSuccessfullyCopyPath,
793
+ status: 'error',
794
+ },
795
+ ],
796
+ };
797
+ });
798
+ it('should call libCodingTestService getValidTestCases', () => {
799
+ service.runTest(resultId, code, true, false, true);
800
+
801
+ expect(
802
+ jest.spyOn(libCodingTestService, 'getValidTestCases')
803
+ ).toHaveBeenCalled();
804
+ });
805
+ it('should call coderunnerApiService runPublicTest$', fakeAsync(() => {
806
+ const runTestData = {
807
+ code: "def countIntegers(n, val, arr):\n smaller = sum(1 for num in arr if num < val)\n equal = sum(1 for num in arr if num == val)\n greater = sum(1 for num in arr if num > val)\n return [smaller, equal, greater]\n\nn = int(input())\nval = int(input())\narr = list(map(int, input().split()))\n\nresult = countIntegers(n, val, arr)\nprint(' '.join(map(str, result)))\n",
808
+ testcases: [
809
+ {
810
+ input: '1\n2\n2',
811
+ solution: '0 1 0',
812
+ },
813
+ {
814
+ input: '1\n2\n3',
815
+ solution: '0 1 1',
816
+ },
817
+ {
818
+ input: 'Custom 1',
819
+ solution: '0 1 0',
820
+ },
821
+ {
822
+ input: 'Custom 2',
823
+ solution: '0 1 1',
824
+ },
825
+ ],
826
+ };
827
+ const runCodeSpy = jest.spyOn(coderunnerApiService, 'runPublicTest$');
828
+
829
+ service.runTest(
830
+ resultId,
831
+ runTestData.code as string,
832
+ true,
833
+ false,
834
+ true
835
+ );
836
+
837
+ tick();
838
+ expect(runCodeSpy).toHaveBeenCalledWith(
839
+ runTestData.code,
840
+ runTestData.testcases,
841
+ LATlanguage + '-' + LATversion
842
+ );
843
+ }));
844
+ it('should emit isLoading false', fakeAsync(() => {
845
+ service.runTest(resultId, code, true, false, true);
846
+
847
+ tick();
848
+ expect(service.isTestResultsLoading()).toBeFalsy();
849
+
850
+ flush();
851
+ }));
852
+ it('should emit returned value to codingTestResults$', fakeAsync(() => {
853
+ service.runTest(resultId, code, true, false, true);
854
+ tick();
855
+
856
+ service.codingTestResults$.subscribe((val) => {
857
+ expect(val).toEqual(LATResultsValue);
858
+ });
859
+
860
+ flush();
861
+ }));
862
+ });
863
+
864
+ describe('and publicPreview === false and preview === true', () => {
865
+ beforeEach(() => {
866
+ runTestResponse = {
867
+ executions: [
868
+ {
869
+ input: '1\n2\n2',
870
+ evaluation: {
871
+ score: 0,
872
+ testcase: true,
873
+ },
874
+ run: {
875
+ stdout: '0 1 0\n',
876
+ stderr: null,
877
+ output: '0 1 0\n',
878
+ signal: null,
879
+ code: null,
880
+ },
881
+ compile: null,
882
+ },
883
+ {
884
+ input: '1\n2\n3',
885
+ evaluation: {
886
+ score: 0,
887
+ testcase: false,
888
+ },
889
+ run: {
890
+ stdout: '0 0 1\n',
891
+ stderr: null,
892
+ output: '0 0 1\n',
893
+ signal: null,
894
+ code: null,
895
+ },
896
+ compile: null,
897
+ },
898
+ {
899
+ input: 'Custom 1',
900
+ evaluation: {
901
+ score: 0,
902
+ testcase: true,
903
+ },
904
+ run: {
905
+ stdout: '0 1 0\n',
906
+ stderr: null,
907
+ output: '0 1 0\n',
908
+ signal: null,
909
+ code: null,
910
+ },
911
+ compile: null,
912
+ },
913
+ {
914
+ input: 'Custom 2',
915
+ evaluation: {
916
+ score: 0,
917
+ testcase: false,
918
+ },
919
+ run: {
920
+ stdout: '0 0 1\n',
921
+ stderr: null,
922
+ output: '0 0 1\n',
923
+ signal: null,
924
+ code: null,
925
+ },
926
+ compile: null,
927
+ },
928
+ ],
929
+ };
930
+ LATResultsValue = {
931
+ resume: { ok: 2, error: 2, total: 4 },
932
+ listResponse: [
933
+ {
934
+ actualOutput: '0 1 0\n',
935
+ logs: executedSuccessfullyCopyPath,
936
+ status: 'passed',
937
+ },
938
+ {
939
+ actualOutput: '0 0 1\n',
940
+ logs: executedSuccessfullyCopyPath,
941
+ status: 'error',
942
+ },
943
+ {
944
+ actualOutput: '0 1 0\n',
945
+ logs: executedSuccessfullyCopyPath,
946
+ status: 'passed',
947
+ },
948
+ {
949
+ actualOutput: '0 0 1\n',
950
+ logs: executedSuccessfullyCopyPath,
951
+ status: 'error',
952
+ },
953
+ ],
954
+ };
955
+ });
956
+ it('should call libCodingTestService getValidTestCases', () => {
957
+ service.runTest(resultId, code, true, false, false, true, id);
958
+
959
+ expect(
960
+ jest.spyOn(libCodingTestService, 'getValidTestCases')
961
+ ).toHaveBeenCalled();
962
+ });
963
+
964
+ it('should track mixpanel event with custom test cases data', fakeAsync(() => {
965
+ const expectedMixpanelEvent = {
966
+ coding_test_uuid: testUuidTransformed,
967
+ coding_test_name: testName,
968
+ coderunner_test_instance: 'practice question',
969
+ custom_testcases_passed: 1,
970
+ custom_testcases_failed: 1,
971
+ custom_testcases_empty: 2,
972
+ example_testcases_passed: 1,
973
+ example_testcases_failed: 1,
974
+ coderunner_response_time: expect.any(Number),
975
+ };
976
+ service.runTest(
977
+ resultId,
978
+ code,
979
+ true,
980
+ false,
981
+ false,
982
+ true,
983
+ id,
984
+ 0,
985
+ testData
986
+ );
987
+ tick();
988
+
989
+ expect(mixpanelSpy).toHaveBeenCalledWith(
990
+ mixpanelTestCasesEvent,
991
+ expectedMixpanelEvent
992
+ );
993
+ flush();
994
+ }));
995
+
996
+ it('should call coderunnerApiService runPreviewTest$', fakeAsync(() => {
997
+ const runTestData = {
998
+ code: "def countIntegers(n, val, arr):\n smaller = sum(1 for num in arr if num < val)\n equal = sum(1 for num in arr if num == val)\n greater = sum(1 for num in arr if num > val)\n return [smaller, equal, greater]\n\nn = int(input())\nval = int(input())\narr = list(map(int, input().split()))\n\nresult = countIntegers(n, val, arr)\nprint(' '.join(map(str, result)))\n",
999
+ testcases: [
1000
+ {
1001
+ input: '1\n2\n2',
1002
+ solution: '0 1 0',
1003
+ },
1004
+ {
1005
+ input: '1\n2\n3',
1006
+ solution: '0 1 1',
1007
+ },
1008
+ {
1009
+ input: 'Custom 1',
1010
+ solution: '0 1 0',
1011
+ },
1012
+ {
1013
+ input: 'Custom 2',
1014
+ solution: '0 1 1',
1015
+ },
1016
+ ],
1017
+ };
1018
+ const runCodeSpy = jest.spyOn(
1019
+ coderunnerApiService,
1020
+ 'runPreviewTest$'
1021
+ );
1022
+
1023
+ service.runTest(
1024
+ resultId,
1025
+ runTestData.code,
1026
+ true,
1027
+ false,
1028
+ false,
1029
+ true,
1030
+ id,
1031
+ testResultId,
1032
+ testData
1033
+ );
1034
+
1035
+ tick();
1036
+ expect(runCodeSpy).toHaveBeenCalledWith(
1037
+ testResultId,
1038
+ runTestData.code,
1039
+ runTestData.testcases,
1040
+ LATlanguage + '-' + LATversion
1041
+ );
1042
+ }));
1043
+ it('should emit isLoading false', fakeAsync(() => {
1044
+ service.runTest(
1045
+ resultId,
1046
+ code,
1047
+ true,
1048
+ false,
1049
+ false,
1050
+ true,
1051
+ id,
1052
+ 0,
1053
+ testData
1054
+ );
1055
+
1056
+ tick();
1057
+ expect(service.isTestResultsLoading()).toBeFalsy();
1058
+
1059
+ flush();
1060
+ }));
1061
+ it('should emit returned value to codingTestResults$', fakeAsync(() => {
1062
+ service.runTest(
1063
+ resultId,
1064
+ code,
1065
+ true,
1066
+ false,
1067
+ false,
1068
+ true,
1069
+ id,
1070
+ 0,
1071
+ testData
1072
+ );
1073
+ tick();
1074
+
1075
+ service.codingTestResults$.subscribe((val) => {
1076
+ expect(val).toEqual(LATResultsValue);
1077
+ });
1078
+
1079
+ flush();
1080
+ }));
1081
+ });
1082
+
1083
+ describe('and publicPreview === false and preview === false', () => {
1084
+ beforeEach(() => {
1085
+ testData = { ...testData, is_preview_mode: false };
1086
+ runTestResponse = {
1087
+ executions: [
1088
+ {
1089
+ input: '1\n2\n2',
1090
+ evaluation: {
1091
+ score: 0,
1092
+ testcase: false,
1093
+ },
1094
+ run: {
1095
+ code: null,
1096
+ output: null,
1097
+ signal: 'SIGKILL',
1098
+ stderr: null,
1099
+ stdout: null,
1100
+ },
1101
+ compile: {
1102
+ stderr: null,
1103
+ },
1104
+ },
1105
+ {
1106
+ input: '1\n2\n3',
1107
+ evaluation: {
1108
+ score: 0,
1109
+ testcase: true,
1110
+ },
1111
+ run: {
1112
+ stdout: '',
1113
+ stderr: null,
1114
+ output: '',
1115
+ signal: null,
1116
+ code: null,
1117
+ },
1118
+ compile: {
1119
+ stderr: null,
1120
+ },
1121
+ },
1122
+ {
1123
+ input: 'Custom 1',
1124
+ evaluation: {
1125
+ score: 0,
1126
+ testcase: true,
1127
+ },
1128
+ run: {
1129
+ stdout: null,
1130
+ stderr: null,
1131
+ output: null,
1132
+ signal: null,
1133
+ code: null,
1134
+ },
1135
+ compile: {
1136
+ stderr: null,
1137
+ },
1138
+ },
1139
+ {
1140
+ input: 'Custom 2',
1141
+ evaluation: {
1142
+ score: 0,
1143
+ testcase: false,
1144
+ },
1145
+ run: {
1146
+ stdout: null,
1147
+ stderr: 'something went wrong',
1148
+ output: null,
1149
+ signal: null,
1150
+ code: null,
1151
+ },
1152
+ compile: {
1153
+ stderr: 'something went wrong',
1154
+ },
1155
+ },
1156
+ ],
1157
+ };
1158
+ LATResultsValue = {
1159
+ resume: { ok: 2, error: 2, total: 4 },
1160
+ listResponse: [
1161
+ {
1162
+ actualOutput: noResponseOutputCopyPath,
1163
+ logs: timeoutErrorCopyPath,
1164
+ status: 'error',
1165
+ },
1166
+ {
1167
+ actualOutput: noneOutputCopyPath,
1168
+ logs: executedSuccessfullyCopyPath,
1169
+ status: 'passed',
1170
+ },
1171
+ {
1172
+ actualOutput: noneOutputCopyPath,
1173
+ logs: executedSuccessfullyCopyPath,
1174
+ status: 'passed',
1175
+ },
1176
+ {
1177
+ actualOutput: noResponseOutputCopyPath,
1178
+ logs: 'something went wrong',
1179
+ status: 'error',
1180
+ },
1181
+ ],
1182
+ };
1183
+ });
1184
+ it('should call libCodingTestService getValidTestCases', () => {
1185
+ service.runTest(resultId, code, true, false, false, false, id);
1186
+
1187
+ expect(
1188
+ jest.spyOn(libCodingTestService, 'getValidTestCases')
1189
+ ).toHaveBeenCalled();
1190
+ });
1191
+
1192
+ it('should track mixpanel event with custom test cases data', fakeAsync(() => {
1193
+ const expectedMixpanelEvent = {
1194
+ coding_test_uuid: testUuidTransformed,
1195
+ coding_test_name: testName,
1196
+ coderunner_test_instance: 'real test',
1197
+ custom_testcases_passed: 1,
1198
+ custom_testcases_failed: 1,
1199
+ custom_testcases_empty: 2,
1200
+ example_testcases_failed: 1,
1201
+ example_testcases_passed: 1,
1202
+ coderunner_response_time: expect.any(Number),
1203
+ };
1204
+
1205
+ service.runTest(
1206
+ resultId,
1207
+ code,
1208
+ true,
1209
+ false,
1210
+ false,
1211
+ false,
1212
+ id,
1213
+ 0,
1214
+ testData
1215
+ );
1216
+ tick();
1217
+
1218
+ expect(mixpanelSpy).toHaveBeenCalledWith(
1219
+ mixpanelTestCasesEvent,
1220
+ expectedMixpanelEvent
1221
+ );
1222
+ flush();
1223
+ }));
1224
+
1225
+ it('should call candidatureApiService sendCodeEvent$', fakeAsync(() => {
1226
+ jest
1227
+ .spyOn(coderunnerApiService, 'runNonPreviewTest$')
1228
+ .mockReturnValue(of(runTestResponse));
1229
+ const runTestData = {
1230
+ code: 'SELECT value FROM test_table;',
1231
+ };
1232
+ const sendEventSpy = jest.spyOn(
1233
+ coderunnerApiService,
1234
+ 'sendCodeEvent$'
1235
+ );
1236
+ const event = {
1237
+ event_type: 'ATTEMPT',
1238
+ attempt_id: '',
1239
+ extra_payload: '',
1240
+ question_result_id: resultId,
1241
+ code: runTestData.code,
1242
+ language: `${service['currentLanguage'].name}-${service['currentLanguage'].version}`,
1243
+ };
1244
+
1245
+ service.runTest(
1246
+ resultId,
1247
+ runTestData.code,
1248
+ true,
1249
+ false,
1250
+ false,
1251
+ false,
1252
+ id,
1253
+ 0,
1254
+ testData
1255
+ );
1256
+
1257
+ tick();
1258
+ expect(sendEventSpy).toHaveBeenCalledWith(event);
1259
+ }));
1260
+
1261
+ it('should call coderunnerApiService runNonPreviewTest$', fakeAsync(() => {
1262
+ const runTestData = {
1263
+ code: "def countIntegers(n, val, arr):\n smaller = sum(1 for num in arr if num < val)\n equal = sum(1 for num in arr if num == val)\n greater = sum(1 for num in arr if num > val)\n return [smaller, equal, greater]\n\nn = int(input())\nval = int(input())\narr = list(map(int, input().split()))\n\nresult = countIntegers(n, val, arr)\nprint(' '.join(map(str, result)))\n",
1264
+ testcases: [
1265
+ {
1266
+ input: '1\n2\n2',
1267
+ solution: '0 1 0',
1268
+ },
1269
+ {
1270
+ input: '1\n2\n3',
1271
+ solution: '0 1 1',
1272
+ },
1273
+ {
1274
+ input: 'Custom 1',
1275
+ solution: '0 1 0',
1276
+ },
1277
+ {
1278
+ input: 'Custom 2',
1279
+ solution: '0 1 1',
1280
+ },
1281
+ ],
1282
+ };
1283
+ const runCodeSpy = jest.spyOn(
1284
+ coderunnerApiService,
1285
+ 'runNonPreviewTest$'
1286
+ );
1287
+
1288
+ service.runTest(
1289
+ resultId,
1290
+ runTestData.code,
1291
+ true,
1292
+ false,
1293
+ false,
1294
+ false,
1295
+ id,
1296
+ 0,
1297
+ testData
1298
+ );
1299
+
1300
+ tick();
1301
+ expect(runCodeSpy).toHaveBeenCalledWith(
1302
+ id,
1303
+ resultId,
1304
+ runTestData.code,
1305
+ runTestData.testcases,
1306
+ LATlanguage + '-' + LATversion
1307
+ );
1308
+ }));
1309
+ it('should emit isLoading false', fakeAsync(() => {
1310
+ service.runTest(
1311
+ resultId,
1312
+ code,
1313
+ true,
1314
+ false,
1315
+ false,
1316
+ false,
1317
+ id,
1318
+ 0,
1319
+ testData
1320
+ );
1321
+
1322
+ tick();
1323
+ expect(service.isTestResultsLoading()).toBeFalsy();
1324
+
1325
+ flush();
1326
+ }));
1327
+ it('should emit returned value to codingTestResults$', fakeAsync(() => {
1328
+ service.runTest(
1329
+ resultId,
1330
+ code,
1331
+ true,
1332
+ false,
1333
+ false,
1334
+ false,
1335
+ id,
1336
+ 0,
1337
+ testData
1338
+ );
1339
+ tick();
1340
+
1341
+ service.codingTestResults$.subscribe((val) => {
1342
+ expect(val).toEqual(LATResultsValue);
1343
+ });
1344
+
1345
+ flush();
1346
+ }));
1347
+ });
1348
+ });
1349
+ });
1350
+
1351
+ describe('when reset run test state summary is called', () => {
1352
+ beforeEach(() => {
1353
+ runTestResponse = {
1354
+ executions: [
1355
+ {
1356
+ input: '1\n2\n2',
1357
+ evaluation: {
1358
+ score: 0,
1359
+ testcase: false,
1360
+ },
1361
+ run: {
1362
+ code: null,
1363
+ output: null,
1364
+ signal: 'SIGKILL',
1365
+ stderr: null,
1366
+ stdout: null,
1367
+ },
1368
+ compile: {
1369
+ stderr: null,
1370
+ },
1371
+ },
1372
+ {
1373
+ input: '1\n2\n3',
1374
+ evaluation: {
1375
+ score: 0,
1376
+ testcase: true,
1377
+ },
1378
+ run: {
1379
+ stdout: '',
1380
+ stderr: null,
1381
+ output: '',
1382
+ signal: null,
1383
+ code: null,
1384
+ },
1385
+ compile: {
1386
+ stderr: null,
1387
+ },
1388
+ },
1389
+ {
1390
+ input: 'Custom 1',
1391
+ evaluation: {
1392
+ score: 0,
1393
+ testcase: true,
1394
+ },
1395
+ run: {
1396
+ stdout: null,
1397
+ stderr: null,
1398
+ output: null,
1399
+ signal: null,
1400
+ code: null,
1401
+ },
1402
+ compile: {
1403
+ stderr: null,
1404
+ },
1405
+ },
1406
+ {
1407
+ input: 'Custom 2',
1408
+ evaluation: {
1409
+ score: 0,
1410
+ testcase: false,
1411
+ },
1412
+ run: {
1413
+ stdout: null,
1414
+ stderr: 'something went wrong',
1415
+ output: null,
1416
+ signal: null,
1417
+ code: null,
1418
+ },
1419
+ compile: {
1420
+ stderr: 'something went wrong',
1421
+ },
1422
+ },
1423
+ ],
1424
+ };
1425
+ });
1426
+
1427
+ it('should set default summary and publish it', fakeAsync(() => {
1428
+ const defaultSummary = {
1429
+ listResponse: [],
1430
+ resume: {
1431
+ ok: 0,
1432
+ error: 0,
1433
+ total: 0,
1434
+ },
1435
+ };
1436
+
1437
+ service.runTest(resultId, code, true, false, true);
1438
+
1439
+ tick();
1440
+ service.resetRunTestSummary();
1441
+
1442
+ service.codingTestResults$.subscribe((summary) => {
1443
+ expect(summary).toEqual(defaultSummary);
1444
+ });
1445
+
1446
+ flush();
1447
+ }));
1448
+ });
1449
+
1450
+ describe('when track config changed is called', () => {
1451
+ let mixpanelSpy: jest.SpyInstance;
1452
+ let props: {
1453
+ coderunner_setting: string;
1454
+ coderunner_setting_new_value: string;
1455
+ coderunner_setting_instance: string;
1456
+ };
1457
+ const mixpanelSettingsEvent = 'Changed Coderunner setting';
1458
+
1459
+ beforeEach(() => {
1460
+ mixpanelSpy = jest.spyOn(mixpanelService, 'track');
1461
+ });
1462
+
1463
+ describe('and when is practice question, theme is changed', () => {
1464
+ it('should call mixpanel with practice question, theme, themeValue', fakeAsync(() => {
1465
+ const setting = 'Color theme';
1466
+ const value = 'dark';
1467
+ libCodingTestServiceMock.configFieldChanged$ = scheduled(
1468
+ of({ [setting]: `theme-${value}` }),
1469
+ asyncScheduler
1470
+ ) as unknown as Observable<null>;
1471
+ props = {
1472
+ coderunner_setting: setting,
1473
+ coderunner_setting_new_value: value,
1474
+ coderunner_setting_instance: 'practice question',
1475
+ };
1476
+ service.trackConfigChanged(true);
1477
+
1478
+ tick();
1479
+
1480
+ expect(mixpanelSpy).toBeCalledWith(mixpanelSettingsEvent, props);
1481
+ }));
1482
+ });
1483
+
1484
+ describe('and when is NOT practice question, fullscreen is changed', () => {
1485
+ it('should call mixpanel with real test, full screen, value', fakeAsync(() => {
1486
+ const setting = 'Full screen';
1487
+ libCodingTestServiceMock.configFieldChanged$ = scheduled(
1488
+ of({ [setting]: true }),
1489
+ asyncScheduler
1490
+ ) as unknown as Observable<null>;
1491
+ props = {
1492
+ coderunner_setting: setting,
1493
+ coderunner_setting_new_value: 'ON',
1494
+ coderunner_setting_instance: 'real test',
1495
+ };
1496
+ service.trackConfigChanged();
1497
+
1498
+ tick();
1499
+
1500
+ expect(mixpanelSpy).toBeCalledWith(mixpanelSettingsEvent, props);
1501
+ }));
1502
+ });
1503
+
1504
+ describe('and when is practice question, font size is changed', () => {
1505
+ it('should call mixpanel with practice question, font, font size', fakeAsync(() => {
1506
+ const setting = 'Font size';
1507
+ libCodingTestServiceMock.configFieldChanged$ = scheduled(
1508
+ of({ [setting]: 12 }),
1509
+ asyncScheduler
1510
+ ) as unknown as Observable<null>;
1511
+ props = {
1512
+ coderunner_setting: setting,
1513
+ coderunner_setting_new_value: '12',
1514
+ coderunner_setting_instance: 'practice question',
1515
+ };
1516
+ service.trackConfigChanged(true);
1517
+
1518
+ tick();
1519
+
1520
+ expect(mixpanelSpy).toBeCalledWith(mixpanelSettingsEvent, props);
1521
+ }));
1522
+ });
1523
+ });
1524
+ });