1
1
import { screen } from "@testing-library/react"
2
2
import { rest } from "msw"
3
3
import React from "react"
4
+ import * as api from "../../api/api"
5
+ import { Template , Workspace , WorkspaceBuild } from "../../api/typesGenerated"
6
+ import { Language } from "../../components/WorkspaceStatusBar/WorkspaceStatusBar"
4
7
import {
8
+ MockCancelingWorkspace ,
9
+ MockDeletedWorkspace ,
10
+ MockDeletingWorkspace ,
5
11
MockFailedWorkspace ,
6
12
MockOutdatedWorkspace ,
13
+ MockStartingWorkspace ,
7
14
MockStoppedWorkspace ,
15
+ MockStoppingWorkspace ,
8
16
MockTemplate ,
9
17
MockWorkspace ,
18
+ MockWorkspaceBuild ,
10
19
renderWithAuth ,
11
20
} from "../../testHelpers/renderHelpers"
12
21
import { server } from "../../testHelpers/server"
13
22
import { WorkspacePage } from "./WorkspacePage"
14
23
24
+ /**
25
+ * Requests and responses related to workspace status are unrelated, so we can't test in the usual way.
26
+ * Instead, test that button clicks produce the correct requests and that responses produce the correct UI.
27
+ * We don't need to test the UI exhaustively because Storybook does that; just enough to prove that the
28
+ * workspaceStatus was calculated correctly.
29
+ */
30
+
31
+ const testButton = async (
32
+ label : string ,
33
+ mock :
34
+ | jest . SpyInstance < Promise < WorkspaceBuild > , [ workspaceId : string , templateVersionId ?: string | undefined ] >
35
+ | jest . SpyInstance < Promise < Template > , [ templateId : string ] > ,
36
+ ) => {
37
+ renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
38
+ const button = await screen . findByText ( label )
39
+ button . click ( )
40
+ expect ( mock ) . toHaveBeenCalled ( )
41
+ }
42
+
43
+ const testStatus = async ( mock : Workspace , label : string ) => {
44
+ server . use (
45
+ rest . get ( `/api/v2/workspaces/${ MockWorkspace . id } ` , ( req , res , ctx ) => {
46
+ return res ( ctx . status ( 200 ) , ctx . json ( mock ) )
47
+ } ) ,
48
+ )
49
+ renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
50
+ const status = await screen . findByRole ( "status" )
51
+ expect ( status ) . toHaveTextContent ( label )
52
+ }
53
+
15
54
describe ( "Workspace Page" , ( ) => {
16
55
it ( "shows a workspace" , async ( ) => {
17
56
renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
@@ -25,54 +64,66 @@ describe("Workspace Page", () => {
25
64
const status = await screen . findByRole ( "status" )
26
65
expect ( status ) . toHaveTextContent ( "Running" )
27
66
} )
28
- it ( "stops the workspace when the user presses Stop" , async ( ) => {
29
- renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
30
- const status = await screen . findByText ( "Running" )
31
- expect ( status ) . toBeDefined ( )
32
- const stopButton = await screen . findByText ( "Stop" )
33
- stopButton . click ( )
34
- const laterStatus = await screen . findByText ( "Stopping" )
35
- expect ( laterStatus ) . toBeDefined ( )
67
+ it ( "requests a stop job when the user presses Stop" , async ( ) => {
68
+ const stopWorkspaceMock = jest
69
+ . spyOn ( api , "stopWorkspace" )
70
+ . mockImplementation ( ( ) => Promise . resolve ( MockWorkspaceBuild ) )
71
+ testButton ( Language . start , stopWorkspaceMock )
72
+ } ) ,
73
+ it ( "requests a start job when the user presses Start" , async ( ) => {
74
+ const startWorkspaceMock = jest
75
+ . spyOn ( api , "startWorkspace" )
76
+ . mockImplementation ( ( ) => Promise . resolve ( MockWorkspaceBuild ) )
77
+ testButton ( Language . start , startWorkspaceMock )
78
+ } ) ,
79
+ it ( "requests a start job when the user presses Retry after trying to start" , async ( ) => {
80
+ const startWorkspaceMock = jest
81
+ . spyOn ( api , "startWorkspace" )
82
+ . mockImplementation ( ( ) => Promise . resolve ( MockWorkspaceBuild ) )
83
+ testButton ( Language . retry , startWorkspaceMock )
84
+ } ) ,
85
+ it ( "requests a stop job when the user presses Retry after trying to stop" , async ( ) => {
86
+ const stopWorkspaceMock = jest
87
+ . spyOn ( api , "stopWorkspace" )
88
+ . mockImplementation ( ( ) => Promise . resolve ( MockWorkspaceBuild ) )
89
+ server . use (
90
+ rest . get ( `/api/v2/workspaces/${ MockWorkspace . id } ` , ( req , res , ctx ) => {
91
+ return res ( ctx . status ( 200 ) , ctx . json ( MockStoppedWorkspace ) )
92
+ } ) ,
93
+ )
94
+ testButton ( Language . start , stopWorkspaceMock )
95
+ } ) ,
96
+ it ( "requests a template when the user presses Update" , async ( ) => {
97
+ const getTemplateMock = jest . spyOn ( api , "getTemplate" ) . mockImplementation ( ( ) => Promise . resolve ( MockTemplate ) )
98
+ server . use (
99
+ rest . get ( `/api/v2/workspaces/${ MockWorkspace . id } ` , ( req , res , ctx ) => {
100
+ return res ( ctx . status ( 200 ) , ctx . json ( MockOutdatedWorkspace ) )
101
+ } ) ,
102
+ )
103
+ testButton ( Language . update , getTemplateMock )
104
+ } ) ,
105
+ it ( "shows the Stopping status when the workspace is stopping" , async ( ) => {
106
+ testStatus ( MockStoppingWorkspace , Language . stopping )
107
+ } )
108
+ it ( "shows the Stopped status when the workspace is stopped" , async ( ) => {
109
+ testStatus ( MockStoppedWorkspace , Language . stopped )
36
110
} )
37
- it ( "starts the workspace when the user presses Start" , async ( ) => {
38
- server . use (
39
- rest . get ( `/api/v2/workspaces/${ MockWorkspace . id } ` , ( req , res , ctx ) => {
40
- return res ( ctx . status ( 200 ) , ctx . json ( MockStoppedWorkspace ) )
41
- } ) ,
42
- )
43
- renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
44
- const startButton = await screen . findByText ( "Start" )
45
- const status = await screen . findByText ( "Stopped" )
46
- expect ( status ) . toBeDefined ( )
47
- startButton . click ( )
48
- const laterStatus = await screen . findByText ( "Building" )
49
- expect ( laterStatus ) . toBeDefined ( )
111
+ it ( "shows the Building status when the workspace is starting" , async ( ) => {
112
+ testStatus ( MockStartingWorkspace , Language . starting )
50
113
} )
51
- it ( "retries starting the workspace when the user presses Retry" , async ( ) => {
52
- // MockFailedWorkspace.latest_build.transition is start so Retry will attempt to start
53
- renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
54
- server . use (
55
- rest . get ( `/api/v2/workspaces/${ MockWorkspace . id } ` , ( req , res , ctx ) => {
56
- return res ( ctx . status ( 200 ) , ctx . json ( MockFailedWorkspace ) )
57
- } ) ,
58
- )
59
- const status = await screen . findByText ( "Build Failed" )
60
- expect ( status ) . toBeDefined ( )
61
- const retryButton = await screen . findByText ( "Retry" )
62
- retryButton . click ( )
63
- const laterStatus = await screen . findByText ( "Building" )
64
- expect ( laterStatus ) . toBeDefined ( )
114
+ it ( "shows the Running status when the workspace is started" , async ( ) => {
115
+ testStatus ( MockWorkspace , Language . started )
65
116
} )
66
- it ( "restarts the workspace when the user presses Update " , async ( ) => {
67
- renderWithAuth ( < WorkspacePage /> , { route : `/workspaces/ ${ MockWorkspace . id } ` , path : "/workspaces/:workspace" } )
68
- server . use (
69
- rest . get ( `/api/v2/workspaces/ ${ MockWorkspace . id } ` , ( req , res , ctx ) => {
70
- return res ( ctx . status ( 200 ) , ctx . json ( MockOutdatedWorkspace ) )
71
- } ) ,
72
- )
73
- const updateButton = await screen . findByText ( "Update" )
74
- updateButton . click ( )
75
- const status = await screen . findByText ( "Building" )
76
- expect ( status ) . toBeDefined ( )
117
+ it ( "shows the Error status when the workspace is failed or canceled " , async ( ) => {
118
+ testStatus ( MockFailedWorkspace , Language . error )
119
+ } )
120
+ it ( "shows the Loading status when the workspace is canceling" , async ( ) => {
121
+ testStatus ( MockCancelingWorkspace , Language . canceling )
122
+ } )
123
+ it ( "shows the Deleting status when the workspace is deleting" , async ( ) => {
124
+ testStatus ( MockDeletingWorkspace , Language . canceling )
125
+ } )
126
+ it ( "shows the Deleted status when the workspace is deleted" , async ( ) => {
127
+ testStatus ( MockDeletedWorkspace , Language . canceling )
77
128
} )
78
129
} )
0 commit comments