apify-test-tools 0.10.2-beta.2 → 0.10.2-beta.3

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 (40) hide show
  1. package/.github/cli/apify-test-tools.mjs +124 -125
  2. package/CHANGELOG.md +1 -0
  3. package/README.md +55 -0
  4. package/bin/affected-actors.ts +166 -0
  5. package/bin/diff-changes.ts +25 -17
  6. package/bin/git.ts +52 -41
  7. package/bin/main.ts +43 -73
  8. package/dist/bin/affected-actors.d.ts +50 -0
  9. package/dist/bin/affected-actors.d.ts.map +1 -0
  10. package/dist/bin/affected-actors.js +89 -0
  11. package/dist/bin/affected-actors.js.map +1 -0
  12. package/dist/bin/diff-changes.d.ts +8 -2
  13. package/dist/bin/diff-changes.d.ts.map +1 -1
  14. package/dist/bin/diff-changes.js +16 -16
  15. package/dist/bin/diff-changes.js.map +1 -1
  16. package/dist/bin/git.d.ts +23 -13
  17. package/dist/bin/git.d.ts.map +1 -1
  18. package/dist/bin/git.js +44 -32
  19. package/dist/bin/git.js.map +1 -1
  20. package/dist/bin/main.js +39 -53
  21. package/dist/bin/main.js.map +1 -1
  22. package/dist/test/bundle/cli-bundle.test.js +9 -2
  23. package/dist/test/bundle/cli-bundle.test.js.map +1 -1
  24. package/dist/test/unit/bin/affected-actors.test.d.ts +2 -0
  25. package/dist/test/unit/bin/affected-actors.test.d.ts.map +1 -0
  26. package/dist/test/unit/bin/affected-actors.test.js +160 -0
  27. package/dist/test/unit/bin/affected-actors.test.js.map +1 -0
  28. package/dist/test/unit/bin/diff-changes.test.js +78 -49
  29. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  30. package/dist/test/unit/bin/git.test.js +50 -53
  31. package/dist/test/unit/bin/git.test.js.map +1 -1
  32. package/dist/test/unit/should-built-and-test.test.js +23 -17
  33. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +1 -1
  36. package/test/bundle/cli-bundle.test.ts +9 -2
  37. package/test/unit/bin/affected-actors.test.ts +190 -0
  38. package/test/unit/bin/diff-changes.test.ts +87 -49
  39. package/test/unit/bin/git.test.ts +56 -53
  40. package/test/unit/should-built-and-test.test.ts +27 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apify-test-tools",
3
- "version": "0.10.2-beta.2",
3
+ "version": "0.10.2-beta.3",
4
4
  "type": "module",
5
5
  "description": "TBD",
6
6
  "repository": {
@@ -130,9 +130,16 @@ describe('CLI bundle', () => {
130
130
  });
131
131
 
132
132
  it('get-affected-actors returns only the Actor whose files changed', () => {
133
- const { status, stdout, stderr } = runCli('get-affected-actors', ...gitRange);
133
+ // `feature` is checked out, and the range always ends at HEAD
134
+ const { status, stdout, stderr } = runCli('get-affected-actors', '--base', 'main');
134
135
  expect(status, stderr).toBe(0);
135
- expect(JSON.parse(stdout)).toMatchObject([{ actorFullName: 'tester/foo', folder: 'actors/foo' }]);
136
+ expect(JSON.parse(stdout)).toMatchObject({
137
+ version: 1,
138
+ head: headSha,
139
+ functionallyChangedActors: [{ actorFullName: 'tester/foo' }],
140
+ // The root README isn't in tester/bar's folder, so it doesn't count for it
141
+ cosmeticallyChangedActors: [],
142
+ });
136
143
  });
137
144
 
138
145
  it('build --dry-run with nothing to build needs no token', () => {
@@ -0,0 +1,190 @@
1
+ import type { MockInstance } from 'vitest';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+
4
+ import { getAffectedActors, toAffectedActorsDocument } from '../../../bin/affected-actors.js';
5
+ import * as DiffChanges from '../../../bin/diff-changes.js';
6
+ import * as Git from '../../../bin/git.js';
7
+ import type { ActorConfig, Commit } from '../../../bin/types.js';
8
+ import * as LoadConfig from '../../../bin/utils/config/load-config.js';
9
+
10
+ // Everything that reads the configs is mocked, so only the identity and name of an Actor matter here
11
+ const actorA = { actorFullName: 'owner/a' } as ActorConfig;
12
+ const actorB = { actorFullName: 'owner/b' } as ActorConfig;
13
+
14
+ const headSha = 'f'.repeat(40);
15
+ const sinceSha = '5'.repeat(40);
16
+ const commit = (sha: string): Commit => ({ sha, author: 'Dev<dev@example.com>', date: 'Date', message: 'msg' });
17
+ const commits = [commit('1'.repeat(40)), commit('2'.repeat(40))];
18
+ const changedFiles = ['src/main.ts', 'CHANGELOG.md'];
19
+
20
+ const selection = { actors: [], ignore: [] };
21
+
22
+ describe('getAffectedActors', () => {
23
+ let changedActorsSpy: MockInstance;
24
+
25
+ beforeEach(() => {
26
+ vi.spyOn(LoadConfig, 'readConfigFile').mockResolvedValue([actorA, actorB]);
27
+ changedActorsSpy = vi
28
+ .spyOn(DiffChanges, 'getChangedActors')
29
+ .mockResolvedValue({ functional: [actorA], cosmetic: [actorB] });
30
+ vi.spyOn(Git, 'resolveCommitSha').mockResolvedValue(headSha);
31
+ vi.spyOn(Git, 'resolveBranchName').mockResolvedValue('feature');
32
+ vi.spyOn(Git, 'getChangedFilesBetween').mockResolvedValue(changedFiles);
33
+ vi.spyOn(Git, 'getChangelogAdditions').mockResolvedValue('- Added foo');
34
+ });
35
+
36
+ it('requires --base or --since', async () => {
37
+ const options = { head: 'HEAD', ...selection };
38
+ await expect(getAffectedActors(options)).rejects.toThrow('Pass --base, --since, or both');
39
+ // An empty --since (e.g. from an empty cache file) counts as not passed
40
+ await expect(getAffectedActors({ ...options, since: '' })).rejects.toThrow('Pass --base, --since, or both');
41
+ });
42
+
43
+ describe('with --base', () => {
44
+ let getCommitsSpy: MockInstance;
45
+
46
+ beforeEach(() => {
47
+ vi.spyOn(Git, 'hasMergeFromTarget').mockResolvedValue(false);
48
+ getCommitsSpy = vi.spyOn(Git, 'getCommits').mockResolvedValue(commits);
49
+ });
50
+
51
+ it('inspects the branch commits after --since', async () => {
52
+ const result = await getAffectedActors({
53
+ head: 'origin/feature',
54
+ base: 'origin/master',
55
+ since: sinceSha,
56
+ ...selection,
57
+ });
58
+
59
+ expect(result).toStrictEqual({
60
+ headSha,
61
+ ref: 'feature',
62
+ commits,
63
+ changedFiles,
64
+ changelog: '- Added foo',
65
+ functionallyChangedActors: [actorA],
66
+ cosmeticallyChangedActors: [actorB],
67
+ });
68
+ expect(getCommitsSpy).toHaveBeenCalledWith({
69
+ sourceBranch: 'origin/feature',
70
+ targetBranch: 'origin/master',
71
+ baseCommit: sinceSha,
72
+ });
73
+ // From the parent of the oldest commit to the newest one, for the files and the changelog alike
74
+ expect(Git.getChangedFilesBetween).toHaveBeenCalledWith(`${commits[0].sha}~`, commits[1].sha);
75
+ expect(Git.getChangelogAdditions).toHaveBeenCalledWith(`${commits[0].sha}~`, commits[1].sha, changedFiles);
76
+ expect(changedActorsSpy).toHaveBeenCalledWith({
77
+ filepathsChanged: changedFiles,
78
+ actorConfigs: [actorA, actorB],
79
+ commits,
80
+ });
81
+ });
82
+
83
+ describe('when the branch merged --base in', () => {
84
+ beforeEach(() => {
85
+ vi.spyOn(Git, 'hasMergeFromTarget').mockResolvedValue(true);
86
+ vi.spyOn(Git, 'getBranchOnlyChangedFiles').mockResolvedValue(['own-file']);
87
+ });
88
+
89
+ const getWithOwnChanges = async (own: DiffChanges.ChangedActors) => {
90
+ changedActorsSpy.mockImplementation(async ({ filepathsChanged }) =>
91
+ filepathsChanged[0] === 'own-file' ? own : { functional: [actorA], cosmetic: [actorB] },
92
+ );
93
+ return getAffectedActors({ head: 'feature', base: 'master', since: sinceSha, ...selection });
94
+ };
95
+
96
+ it("classifies the branch's own files against the whole branch, ignoring --since", async () => {
97
+ await getWithOwnChanges({ functional: [actorA], cosmetic: [] });
98
+ expect(changedActorsSpy).toHaveBeenCalledWith({
99
+ filepathsChanged: ['own-file'],
100
+ actorConfigs: [actorA, actorB],
101
+ commits,
102
+ });
103
+ expect(getCommitsSpy).toHaveBeenCalledWith({ sourceBranch: 'feature', targetBranch: 'master' });
104
+ });
105
+
106
+ it('reports everything when the branch has functional changes of its own', async () => {
107
+ const result = await getWithOwnChanges({ functional: [actorA], cosmetic: [] });
108
+ expect(result.functionallyChangedActors).toStrictEqual([actorA]);
109
+ expect(result.cosmeticallyChangedActors).toStrictEqual([actorB]);
110
+ });
111
+
112
+ it('reports only cosmetic Actors when its own changes are only cosmetic', async () => {
113
+ const result = await getWithOwnChanges({ functional: [], cosmetic: [actorB] });
114
+ expect(result.functionallyChangedActors).toStrictEqual([]);
115
+ expect(result.cosmeticallyChangedActors).toStrictEqual([actorB]);
116
+ });
117
+
118
+ it('reports nothing when it has no changes of its own', async () => {
119
+ const result = await getWithOwnChanges({ functional: [], cosmetic: [] });
120
+ expect(result.functionallyChangedActors).toStrictEqual([]);
121
+ expect(result.cosmeticallyChangedActors).toStrictEqual([]);
122
+ // The range is still reported
123
+ expect(result.commits).toStrictEqual(commits);
124
+ });
125
+ });
126
+ });
127
+
128
+ describe('with --since only', () => {
129
+ let resolveBaseSpy: MockInstance;
130
+ let commitsBetweenSpy: MockInstance;
131
+
132
+ beforeEach(() => {
133
+ resolveBaseSpy = vi.spyOn(Git, 'resolveReleaseBaseCommit').mockResolvedValue(sinceSha);
134
+ commitsBetweenSpy = vi.spyOn(Git, 'getCommitsBetween').mockResolvedValue(commits);
135
+ });
136
+
137
+ it('inspects everything after --since up to --head', async () => {
138
+ const result = await getAffectedActors({ head: 'release', since: 'HEAD~2', ...selection });
139
+
140
+ expect(result).toStrictEqual({
141
+ headSha,
142
+ ref: 'feature',
143
+ commits,
144
+ changedFiles,
145
+ changelog: '- Added foo',
146
+ functionallyChangedActors: [actorA],
147
+ cosmeticallyChangedActors: [actorB],
148
+ });
149
+ expect(resolveBaseSpy).toHaveBeenCalledWith('HEAD~2', 'release');
150
+ expect(commitsBetweenSpy).toHaveBeenCalledWith(sinceSha, headSha);
151
+ expect(Git.getChangedFilesBetween).toHaveBeenCalledWith(sinceSha, headSha);
152
+ expect(Git.getChangelogAdditions).toHaveBeenCalledWith(sinceSha, headSha, changedFiles);
153
+ });
154
+
155
+ it('has no commits when head is the --since commit', async () => {
156
+ resolveBaseSpy.mockResolvedValue(headSha);
157
+
158
+ const result = await getAffectedActors({ head: 'HEAD', since: headSha, ...selection });
159
+
160
+ expect(result.commits).toStrictEqual([]);
161
+ // Empty `git log x..x` output doesn't parse as a commit, so it's never run
162
+ expect(commitsBetweenSpy).not.toHaveBeenCalled();
163
+ });
164
+ });
165
+ });
166
+
167
+ describe('toAffectedActorsDocument', () => {
168
+ it('keeps only the Actor names, the config file stays the source of truth for the rest', () => {
169
+ expect(
170
+ toAffectedActorsDocument({
171
+ headSha,
172
+ ref: null,
173
+ commits,
174
+ changedFiles: ['src/main.ts'],
175
+ changelog: null,
176
+ functionallyChangedActors: [actorA],
177
+ cosmeticallyChangedActors: [actorB],
178
+ }),
179
+ ).toStrictEqual({
180
+ version: 1,
181
+ ref: null,
182
+ head: headSha,
183
+ commits,
184
+ changedFiles: ['src/main.ts'],
185
+ changelog: null,
186
+ functionallyChangedActors: [{ actorFullName: 'owner/a' }],
187
+ cosmeticallyChangedActors: [{ actorFullName: 'owner/b' }],
188
+ });
189
+ });
190
+ });