1import {mount, flushPromises} from '@vue/test-utils';
2import RepoActionView from './RepoActionView.vue';
3
4test('processes ##[group] and ##[endgroup]', async () => {
5 Object.defineProperty(document.documentElement, 'lang', {value: 'en'});
6 vi.spyOn(global, 'fetch').mockImplementation((url, opts) => {
7 const artifacts_value = {
8 artifacts: [],
9 };
10 const stepsLog_value = [
11 {
12 step: 0,
13 cursor: 0,
14 lines: [
15 {index: 1, message: '##[group]Test group', timestamp: 0},
16 {index: 2, message: 'A test line', timestamp: 0},
17 {index: 3, message: '##[endgroup]', timestamp: 0},
18 {index: 4, message: 'A line outside the group', timestamp: 0},
19 ],
20 },
21 ];
22 const jobs_value = {
23 state: {
24 run: {
25 status: 'success',
26 commit: {
27 pusher: {},
28 },
29 },
30 currentJob: {
31 steps: [
32 {
33 summary: 'Test Job',
34 duration: '1s',
35 status: 'success',
36 },
37 ],
38 },
39 },
40 logs: {
41 stepsLog: opts.body?.includes('"cursor":null') ? stepsLog_value : [],
42 },
43 };
44
45 return Promise.resolve({
46 ok: true,
47 json: vi.fn().mockResolvedValue(
48 url.endsWith('/artifacts') ? artifacts_value : jobs_value,
49 ),
50 });
51 });
52
53 const wrapper = mount(RepoActionView, {
54 props: {
55 jobIndex: '1',
56 locale: {
57 approve: '',
58 cancel: '',
59 rerun: '',
60 artifactsTitle: '',
61 areYouSure: '',
62 confirmDeleteArtifact: '',
63 rerun_all: '',
64 showTimeStamps: '',
65 showLogSeconds: '',
66 showFullScreen: '',
67 downloadLogs: '',
68 status: {
69 unknown: '',
70 waiting: '',
71 running: '',
72 success: '',
73 failure: '',
74 cancelled: '',
75 skipped: '',
76 blocked: '',
77 },
78 },
79 },
80 });
81 await flushPromises();
82 await wrapper.get('.job-step-summary').trigger('click');
83 await flushPromises();
84
85 // Test if header was loaded correctly
86 expect(wrapper.get('.step-summary-msg').text()).toEqual('Test Job');
87
88 // Check if 3 lines where rendered
89 expect(wrapper.findAll('.job-log-line').length).toEqual(3);
90
91 // Check if line 1 contains the group header
92 expect(wrapper.get('.job-log-line:nth-of-type(1) > details.log-msg').text()).toEqual('Test group');
93
94 // Check if right after the header line exists a log list
95 expect(wrapper.find('.job-log-line:nth-of-type(1) + .job-log-list.hidden').exists()).toBe(true);
96
97 // Check if inside the loglist exist exactly one log line
98 expect(wrapper.findAll('.job-log-list > .job-log-line').length).toEqual(1);
99
100 // Check if inside the loglist is an logline with our second logline
101 expect(wrapper.get('.job-log-list > .job-log-line > .log-msg').text()).toEqual('A test line');
102
103 // Check if after the log list exists another log line
104 expect(wrapper.get('.job-log-list + .job-log-line > .log-msg').text()).toEqual('A line outside the group');
105});
106
107test('load multiple steps on a finished action', async () => {
108 Object.defineProperty(document.documentElement, 'lang', {value: 'en'});
109 vi.spyOn(global, 'fetch').mockImplementation((url, opts) => {
110 if (url.endsWith('/artifacts')) {
111 return Promise.resolve({
112 ok: true,
113 json: vi.fn().mockResolvedValue(
114 {
115 artifacts: [],
116 },
117 ),
118 });
119 }
120
121 const postBody = JSON.parse(opts.body);
122 const stepsLog_value = [];
123 for (const cursor of postBody.logCursors) {
124 if (cursor.expanded) {
125 stepsLog_value.push(
126 {
127 step: cursor.step,
128 cursor: 0,
129 lines: [
130 {index: 1, message: `Step #${cursor.step + 1} Log #1`, timestamp: 0},
131 {index: 1, message: `Step #${cursor.step + 1} Log #2`, timestamp: 0},
132 {index: 1, message: `Step #${cursor.step + 1} Log #3`, timestamp: 0},
133 ],
134 },
135 );
136 }
137 }
138 const jobs_value = {
139 state: {
140 run: {
141 status: 'success',
142 commit: {
143 pusher: {},
144 },
145 },
146 currentJob: {
147 steps: [
148 {
149 summary: 'Test Step #1',
150 duration: '1s',
151 status: 'success',
152 },
153 {
154 summary: 'Test Step #2',
155 duration: '1s',
156 status: 'success',
157 },
158 ],
159 },
160 },
161 logs: {
162 stepsLog: opts.body?.includes('"cursor":null') ? stepsLog_value : [],
163 },
164 };
165
166 return Promise.resolve({
167 ok: true,
168 json: vi.fn().mockResolvedValue(
169 jobs_value,
170 ),
171 });
172 });
173
174 const wrapper = mount(RepoActionView, {
175 props: {
176 actionsURL: 'https://example.com/example-org/example-repo/actions',
177 runIndex: '1',
178 jobIndex: '2',
179 locale: {
180 approve: '',
181 cancel: '',
182 rerun: '',
183 artifactsTitle: '',
184 areYouSure: '',
185 confirmDeleteArtifact: '',
186 rerun_all: '',
187 showTimeStamps: '',
188 showLogSeconds: '',
189 showFullScreen: '',
190 downloadLogs: '',
191 status: {
192 unknown: '',
193 waiting: '',
194 running: '',
195 success: '',
196 failure: '',
197 cancelled: '',
198 skipped: '',
199 blocked: '',
200 },
201 },
202 },
203 });
204 await flushPromises();
205 // Click on both steps to start their log loading in fast succession...
206 await wrapper.get('.job-step-section:nth-of-type(1) .job-step-summary').trigger('click');
207 await wrapper.get('.job-step-section:nth-of-type(2) .job-step-summary').trigger('click');
208 await flushPromises();
209
210 // Verify both step's logs were loaded
211 expect(wrapper.get('.job-step-section:nth-of-type(1) .job-log-line:nth-of-type(1) .log-msg').text()).toEqual('Step #1 Log #1');
212 expect(wrapper.get('.job-step-section:nth-of-type(1) .job-log-line:nth-of-type(2) .log-msg').text()).toEqual('Step #1 Log #2');
213 expect(wrapper.get('.job-step-section:nth-of-type(1) .job-log-line:nth-of-type(3) .log-msg').text()).toEqual('Step #1 Log #3');
214 expect(wrapper.get('.job-step-section:nth-of-type(2) .job-log-line:nth-of-type(1) .log-msg').text()).toEqual('Step #2 Log #1');
215 expect(wrapper.get('.job-step-section:nth-of-type(2) .job-log-line:nth-of-type(2) .log-msg').text()).toEqual('Step #2 Log #2');
216 expect(wrapper.get('.job-step-section:nth-of-type(2) .job-log-line:nth-of-type(3) .log-msg').text()).toEqual('Step #2 Log #3');
217});