@testgorilla/tgo-ai-interview-test 0.0.1 → 2.0.0

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 CHANGED
@@ -21,7 +21,8 @@
21
21
  "prefix": "tgo",
22
22
  "style": "kebab-case"
23
23
  }
24
- ]
24
+ ],
25
+ "@angular-eslint/prefer-standalone": "off"
25
26
  }
26
27
  },
27
28
  {
@@ -43,4 +44,3 @@
43
44
  }
44
45
  ]
45
46
  }
46
-
package/README.md CHANGED
@@ -32,6 +32,38 @@ import { AiInterviewTestComponent } from '@testgorilla/tgo-ai-interview-test';
32
32
  export class MyComponent {}
33
33
  ```
34
34
 
35
+ ## Assets (translations)
36
+
37
+ This package ships its translations under `assets/i18n`. Consumer apps must copy these assets into their build output so Transloco can load them at runtime.
38
+
39
+ - **Angular CLI / Nx**: add an `assets` entry pointing at the package:
40
+
41
+ ```json
42
+ {
43
+ "assets": [
44
+ "src/favicon.ico",
45
+ "src/assets",
46
+ {
47
+ "glob": "**/*",
48
+ "input": "node_modules/@testgorilla/tgo-ai-interview-test/assets",
49
+ "output": "assets/tgo-ai-interview-test"
50
+ }
51
+ ]
52
+ }
53
+ ```
54
+
55
+ If you develop inside this repo (consuming the workspace sources), also include the local path:
56
+
57
+ ```json
58
+ {
59
+ "glob": "**/*",
60
+ "input": "packages/tgo-ai-interview-test/src/assets",
61
+ "output": "assets/tgo-ai-interview-test"
62
+ }
63
+ ```
64
+
65
+ After adding the asset entries, rebuild/re-serve your app so `/assets/tgo-ai-interview-test/i18n/en.json` is available.
66
+
35
67
  ## API
36
68
 
37
69
  ### Inputs
package/jest.config.ts CHANGED
@@ -6,7 +6,8 @@ export default {
6
6
  testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/*.spec.[jt]s?(x)'],
7
7
  testPathIgnorePatterns: ['/node_modules/', '/src/lib/models/'],
8
8
  moduleNameMapper: {
9
- '^@testgorilla/tgo-ui$': '<rootDir>/../tgo-test-shared/src/test-mocks/tgo-ui.mock.ts',
9
+ '^@testgorilla/tgo-ui$': '<rootDir>/../shared/src/test-mocks/tgo-ui.mock.ts',
10
+ '^@testgorilla/tgo-test-shared$': '<rootDir>/src/shared/index.ts',
10
11
  },
11
12
  transform: {
12
13
  '^.+\\.(ts|mjs|js|html)$': [
@@ -26,4 +27,3 @@ export default {
26
27
  'jest-preset-angular/build/serializers/html-comment',
27
28
  ],
28
29
  };
29
-
package/package.json CHANGED
@@ -1,25 +1,19 @@
1
1
  {
2
2
  "name": "@testgorilla/tgo-ai-interview-test",
3
- "version": "0.0.1",
3
+ "version": "2.0.0",
4
4
  "peerDependencies": {
5
- "@angular/common": "~18.2.13",
6
- "@angular/core": "~18.2.13",
7
- "@angular/animations": "~18.2.13",
5
+ "@angular/common": "~19.2.17",
6
+ "@angular/core": "~19.2.17",
7
+ "@angular/animations": "~19.2.17",
8
8
  "@ngneat/transloco": "~4.3.0",
9
- "@testgorilla/tgo-ui": "~3.14.10",
10
- "@testgorilla/tgo-test-shared": "~0.0.1",
9
+ "@testgorilla/tgo-ui": "~4.0.0",
11
10
  "@daily-co/daily-js": "^0.79.0",
12
- "jest-preset-angular": "~14.2.4",
11
+ "jest-preset-angular": "14.4.2",
13
12
  "rxjs": "~7.8.1"
14
13
  },
15
14
  "typings": "src/lib/types",
16
15
  "sideEffects": false,
17
16
  "license": "PROPRIETARY",
18
- "publishConfig": {
19
- "access": "restricted",
20
- "registry": "https://registry.npmjs.org/"
21
- },
22
17
  "displayName": "AI Interview",
23
18
  "description": "AI Interview component"
24
19
  }
25
-
package/project.json CHANGED
@@ -7,6 +7,18 @@
7
7
  "tags": [],
8
8
  "targets": {
9
9
  "build": {
10
+ "executor": "nx:run-commands",
11
+ "outputs": ["{workspaceRoot}/dist/packages/tgo-ai-interview-test"],
12
+ "options": {
13
+ "commands": [
14
+ "nx run tgo-ai-interview-test:package",
15
+ "node scripts/replace-shared-alias.js dist/packages/tgo-ai-interview-test @testgorilla/tgo-test-shared"
16
+ ],
17
+ "parallel": false,
18
+ "forwardAllArgs": false
19
+ }
20
+ },
21
+ "package": {
10
22
  "executor": "@nx/angular:package",
11
23
  "outputs": ["{workspaceRoot}/dist/{projectRoot}"],
12
24
  "options": {
@@ -34,4 +46,3 @@
34
46
  }
35
47
  }
36
48
  }
37
-
@@ -74,24 +74,25 @@ describe('AiInterviewTestComponent', () => {
74
74
  AiInterviewTestComponent,
75
75
  ],
76
76
  schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA],
77
+ providers: [
78
+ { provide: TranslocoService, useValue: transLocoServiceMock },
79
+ { provide: MediaService, useValue: mockedMediaService },
80
+ {
81
+ provide: ChangeDetectorRef,
82
+ useValue: { markForCheck: jest.fn() },
83
+ },
84
+ {
85
+ provide: ThemeService,
86
+ useValue: {
87
+ uiTheme: 'dark',
88
+ getCompanyColor: jest.fn().mockReturnValue('#D410AA'),
89
+ },
90
+ },
91
+ ],
77
92
  })
78
93
  .overrideComponent(AiInterviewTestComponent, {
79
- add: {
80
- providers: [
81
- { provide: TranslocoService, useValue: transLocoServiceMock },
82
- { provide: MediaService, useValue: mockedMediaService },
83
- {
84
- provide: ChangeDetectorRef,
85
- useValue: { markForCheck: jest.fn() },
86
- },
87
- {
88
- provide: ThemeService,
89
- useValue: {
90
- uiTheme: 'dark',
91
- getCompanyColor: jest.fn().mockReturnValue('#D410AA'),
92
- },
93
- },
94
- ],
94
+ set: {
95
+ template: '',
95
96
  },
96
97
  })
97
98
  .compileComponents();
@@ -43,37 +43,36 @@ import {
43
43
  import { IQuestionDataContract } from '../../models';
44
44
 
45
45
  @Component({
46
- selector: 'tgo-ai-interview-test',
47
- templateUrl: './ai-interview-test.component.html',
48
- styleUrl: './ai-interview-test.component.scss',
49
- animations: [
50
- trigger('fadeInFadeOut', [
51
- transition(':enter', [
52
- style({ opacity: 0 }),
53
- animate('600ms', style({ opacity: 1 })),
54
- ]),
55
- transition(':leave', [animate('600ms', style({ opacity: 0 }))]),
56
- ]),
57
- ],
58
- standalone: true,
59
- imports: [
60
- TranslocoModule,
61
- ButtonComponentModule,
62
- IconComponentModule,
63
- CommonModule,
64
- AudioAnimationComponent,
65
- InterviewStreamComponent,
66
- ],
67
- providers: [
68
- TranslocoLazyModuleUtils.getScopeProvider(
69
- 'tgo-ai-interview-test',
70
- getAvailableLangs(),
71
- ROOT_TRANSLATIONS_SCOPE,
72
- (lang: string) => import(`../../../assets/i18n/${lang}.json`)
73
- ),
74
- DialogService,
75
- ThemeService,
76
- ],
46
+ selector: 'tgo-ai-interview-test',
47
+ templateUrl: './ai-interview-test.component.html',
48
+ styleUrl: './ai-interview-test.component.scss',
49
+ animations: [
50
+ trigger('fadeInFadeOut', [
51
+ transition(':enter', [
52
+ style({ opacity: 0 }),
53
+ animate('600ms', style({ opacity: 1 })),
54
+ ]),
55
+ transition(':leave', [animate('600ms', style({ opacity: 0 }))]),
56
+ ]),
57
+ ],
58
+ imports: [
59
+ TranslocoModule,
60
+ ButtonComponentModule,
61
+ IconComponentModule,
62
+ CommonModule,
63
+ AudioAnimationComponent,
64
+ InterviewStreamComponent,
65
+ ],
66
+ providers: [
67
+ TranslocoLazyModuleUtils.getScopeProvider('tgo-ai-interview-test', getAvailableLangs(), ROOT_TRANSLATIONS_SCOPE, (lang: string) => {
68
+ // Fetch from app assets; demo app copies the library assets to
69
+ // /assets/tgo-ai-interview-test via project.json.
70
+ const url = new URL(`assets/tgo-ai-interview-test/i18n/${lang}.json`, document.baseURI).href;
71
+ return fetch(url).then((res) => res.json());
72
+ }),
73
+ DialogService,
74
+ ThemeService,
75
+ ]
77
76
  })
78
77
  export class AiInterviewTestComponent
79
78
  implements OnInit, OnDestroy, IQuestionDataContract
@@ -22,32 +22,6 @@ class MediaStreamTrackMock {
22
22
  }
23
23
  }
24
24
 
25
- // Mock Daily.co
26
- jest.mock('@daily-co/daily-js', () => {
27
- const mockCallObject = {
28
- on: jest.fn().mockReturnThis(),
29
- off: jest.fn().mockReturnThis(),
30
- join: jest.fn().mockResolvedValue(undefined),
31
- leave: jest.fn(),
32
- destroy: jest.fn(),
33
- stopRecording: jest.fn(),
34
- setInputDevicesAsync: jest.fn().mockResolvedValue(undefined),
35
- startRecording: jest.fn(),
36
- sendAppMessage: jest.fn(),
37
- };
38
-
39
- const mockDailyIframe = {
40
- getCallInstance: jest.fn().mockReturnValue(null),
41
- createCallObject: jest.fn().mockReturnValue(mockCallObject),
42
- };
43
-
44
- return {
45
- __esModule: true,
46
- default: mockDailyIframe,
47
- DailyIframe: mockDailyIframe,
48
- };
49
- });
50
-
51
25
  describe('InterviewStreamComponent', () => {
52
26
  let component: InterviewStreamComponent;
53
27
  let fixture: ComponentFixture<InterviewStreamComponent>;
@@ -46,11 +46,10 @@ interface EventData {
46
46
  }
47
47
 
48
48
  @Component({
49
- selector: 'tgo-interview-stream',
50
- templateUrl: './interview-stream.component.html',
51
- styleUrls: ['./interview-stream.component.scss'],
52
- standalone: true,
53
- imports: [CommonModule, InterviewVideoComponent],
49
+ selector: 'tgo-interview-stream',
50
+ templateUrl: './interview-stream.component.html',
51
+ styleUrls: ['./interview-stream.component.scss'],
52
+ imports: [CommonModule, InterviewVideoComponent]
54
53
  })
55
54
  export class InterviewStreamComponent implements OnInit, OnDestroy {
56
55
  @Input() conversationUrl: string | undefined;
@@ -2,11 +2,10 @@ import { Component, Input, OnInit, SimpleChanges, OnChanges } from '@angular/cor
2
2
  import { CommonModule } from '@angular/common';
3
3
 
4
4
  @Component({
5
- selector: 'tgo-interview-video',
6
- templateUrl: './interview-video.component.html',
7
- styleUrls: ['./interview-video.component.scss'],
8
- standalone: true,
9
- imports: [CommonModule],
5
+ selector: 'tgo-interview-video',
6
+ templateUrl: './interview-video.component.html',
7
+ styleUrls: ['./interview-video.component.scss'],
8
+ imports: [CommonModule]
10
9
  })
11
10
  export class InterviewVideoComponent implements OnInit, OnChanges {
12
11
  @Input() videoTrack: MediaStreamTrack | undefined;
package/src/test-setup.ts CHANGED
@@ -1,4 +1,6 @@
1
- import 'jest-preset-angular/setup-jest';
1
+ import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
2
+
3
+ setupZoneTestEnv();
2
4
 
3
5
  // Mock HTMLMediaElement.play() for jsdom
4
6
  Object.defineProperty(HTMLMediaElement.prototype, 'play', {
@@ -8,21 +10,67 @@ Object.defineProperty(HTMLMediaElement.prototype, 'play', {
8
10
 
9
11
  // Mock @daily-co/daily-js
10
12
  jest.mock('@daily-co/daily-js', () => {
13
+ const mockCallObject = {
14
+ on: jest.fn().mockReturnThis(),
15
+ off: jest.fn().mockReturnThis(),
16
+ join: jest.fn().mockResolvedValue(undefined),
17
+ leave: jest.fn(),
18
+ destroy: jest.fn(),
19
+ stopRecording: jest.fn(),
20
+ setInputDevicesAsync: jest.fn().mockResolvedValue(undefined),
21
+ startRecording: jest.fn(),
22
+ sendAppMessage: jest.fn(),
23
+ };
24
+
25
+ const mockDailyIframe = {
26
+ getCallInstance: jest.fn().mockReturnValue(null),
27
+ createCallObject: jest.fn().mockReturnValue(mockCallObject),
28
+ };
29
+
11
30
  return {
12
- default: jest.fn().mockImplementation(() => ({
13
- createCallObject: jest.fn().mockReturnValue({
14
- join: jest.fn(),
15
- leave: jest.fn(),
16
- destroy: jest.fn(),
17
- setInputDevicesAsync: jest.fn(),
18
- startRecording: jest.fn(),
19
- stopRecording: jest.fn(),
20
- sendAppMessage: jest.fn(),
21
- on: jest.fn(),
22
- off: jest.fn(),
23
- }),
24
- getCallInstance: jest.fn(),
25
- })),
31
+ __esModule: true,
32
+ default: mockDailyIframe,
33
+ DailyIframe: mockDailyIframe,
26
34
  };
27
35
  });
28
36
 
37
+ // Global cleanup for media elements after each test
38
+ afterEach(() => {
39
+ // Clean up all audio and video elements in the DOM
40
+ const audioElements = Array.from(document.querySelectorAll('audio'));
41
+ const videoElements = Array.from(document.querySelectorAll('video'));
42
+
43
+ [...audioElements, ...videoElements].forEach((element) => {
44
+ const mediaElement = element as HTMLMediaElement;
45
+ try {
46
+ mediaElement.pause();
47
+ mediaElement.src = '';
48
+ mediaElement.srcObject = null;
49
+ // Remove event listeners by cloning
50
+ const newElement = mediaElement.cloneNode(false);
51
+ mediaElement.parentNode?.replaceChild(newElement, mediaElement);
52
+ } catch (error) {
53
+ // Ignore errors during cleanup
54
+ }
55
+ });
56
+
57
+ // Clean up MediaStream tracks
58
+ if (window.MediaStream) {
59
+ // Stop any active MediaStream tracks
60
+ const streams = Array.from(document.querySelectorAll('video, audio'));
61
+ streams.forEach((element) => {
62
+ const mediaElement = element as HTMLMediaElement;
63
+ if (mediaElement.srcObject instanceof MediaStream) {
64
+ mediaElement.srcObject.getTracks().forEach((track) => {
65
+ track.stop();
66
+ });
67
+ mediaElement.srcObject = null;
68
+ }
69
+ });
70
+ }
71
+
72
+ // Revoke any object URLs that might have been created
73
+ // Note: This is a best-effort cleanup since we can't track all created URLs
74
+ // Components should clean up their own object URLs in ngOnDestroy
75
+ });
76
+
package/tsconfig.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es2022"
3
+ "target": "es2022",
4
+ "paths": {
5
+ "@testgorilla/tgo-test-shared": ["./src/shared/index.ts"]
6
+ }
4
7
  },
5
8
  "files": [],
6
9
  "include": [],
package/tsconfig.lib.json CHANGED
@@ -5,11 +5,16 @@
5
5
  "declaration": true,
6
6
  "declarationMap": true,
7
7
  "inlineSources": true,
8
- "types": [
9
- "node",
10
- ]
8
+ "baseUrl": "../../",
9
+ "moduleResolution": "node",
10
+ "paths": {
11
+ "@testgorilla/tgo-test-shared": ["packages/tgo-ai-interview-test/src/shared/index.ts"]
12
+ }
13
+ },
14
+ "angularCompilerOptions": {
15
+ "preserveWhitespaces": false
11
16
  },
12
17
  "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"],
13
- "include": ["src/**/*.ts"]
18
+ "include": ["src/**/*.ts", "src/shared/**/*.ts"]
14
19
  }
15
20
 
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "extends": "./tsconfig.lib.json",
3
3
  "compilerOptions": {
4
- "declarationMap": false
4
+ "declarationMap": false,
5
+ "rootDir": "../../"
5
6
  },
6
7
  "angularCompilerOptions": {
7
8
  "compilationMode": "partial"
@@ -4,10 +4,14 @@
4
4
  "outDir": "../../dist/out-tsc",
5
5
  "module": "commonjs",
6
6
  "target": "es2016",
7
- "types": ["jest", "node"]
7
+ "types": ["jest", "node"],
8
+ "baseUrl": "../../",
9
+ "paths": {
10
+ "@testgorilla/tgo-test-shared": ["packages/tgo-ai-interview-test/src/shared/index.ts"]
11
+ }
8
12
  },
9
13
  "files": ["src/test-setup.ts"],
10
- "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"],
14
+ "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts", "src/shared/**/*.ts"],
11
15
  "exclude": ["src/lib/models/test.ts"]
12
16
  }
13
17