Skip to content

Commit 6e4a0de

Browse files
piehLekoArts
andauthored
chore: pin xstate (#36398)
Co-authored-by: LekoArts <[email protected]>
1 parent e477938 commit 6e4a0de

File tree

8 files changed

+222
-20
lines changed

8 files changed

+222
-20
lines changed

packages/gatsby-source-filesystem/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"mime": "^2.5.2",
1717
"pretty-bytes": "^5.4.1",
1818
"valid-url": "^1.0.9",
19-
"xstate": "^4.26.1"
19+
"xstate": "4.32.1"
2020
},
2121
"devDependencies": {
2222
"@babel/cli": "^7.15.4",
@@ -47,4 +47,4 @@
4747
"engines": {
4848
"node": ">=14.15.0"
4949
}
50-
}
50+
}

packages/gatsby/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
"webpack-merge": "^5.8.0",
170170
"webpack-stats-plugin": "^1.0.3",
171171
"webpack-virtual-modules": "^0.3.2",
172-
"xstate": "^4.26.0",
172+
"xstate": "4.32.1",
173173
"yaml-loader": "^0.6.0"
174174
},
175175
"devDependencies": {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import { queryRunningMachine } from "../query-running"
2+
import { queryActions } from "../query-running/actions"
3+
import { interpret, Interpreter } from "xstate"
4+
import { IProgram } from "../../commands/types"
5+
import { store } from "../../redux"
6+
import reporter from "gatsby-cli/lib/reporter"
7+
import pDefer from "p-defer"
8+
import { IGroupedQueryIds } from "../../services/types"
9+
10+
const services = {
11+
extractQueries: jest.fn(async () => {}),
12+
writeOutRequires: jest.fn(async () => {}),
13+
calculateDirtyQueries: jest.fn(
14+
async (): Promise<{
15+
queryIds: IGroupedQueryIds
16+
}> => {
17+
return {
18+
queryIds: {
19+
pageQueryIds: [],
20+
staticQueryIds: [],
21+
},
22+
}
23+
}
24+
),
25+
}
26+
27+
const machine = queryRunningMachine.withConfig(
28+
{
29+
actions: queryActions,
30+
services,
31+
},
32+
{
33+
program: {} as IProgram,
34+
store,
35+
reporter,
36+
pendingQueryRuns: new Set([`/`]),
37+
}
38+
)
39+
40+
const resetMocks = (mocks: Record<string, jest.Mock>): void =>
41+
Object.values(mocks).forEach(mock => mock.mockClear())
42+
43+
const resetAllMocks = (): void => {
44+
resetMocks(services)
45+
}
46+
47+
const finished = async (
48+
service: Interpreter<any, any, any, any, any>
49+
): Promise<void> =>
50+
new Promise(resolve => {
51+
service.onDone(() => resolve())
52+
})
53+
54+
function debug(service: Interpreter<any, any, any, any, any>): void {
55+
let last: any
56+
57+
service.onTransition(state => {
58+
if (!last) {
59+
last = state
60+
} else if (!state.changed) {
61+
return
62+
}
63+
64+
reporter.info(
65+
`---onTransition---\n${require(`util`).inspect(
66+
{
67+
stateValue: state.value,
68+
event: state.event,
69+
pendingQueryRuns: state.context.pendingQueryRuns,
70+
changedStateValue: state.value !== last.value,
71+
},
72+
{ depth: Infinity }
73+
)}`
74+
)
75+
last = state
76+
})
77+
}
78+
79+
expect.extend({
80+
toHaveInSet(received, item) {
81+
if (received.has(item)) {
82+
return {
83+
pass: true,
84+
message: (): string =>
85+
`Expected ${Array.from(received)} not to contain ${item}`,
86+
}
87+
} else {
88+
return {
89+
pass: false,
90+
message: (): string =>
91+
`Expected ${Array.from(received)} not to contain ${item}`,
92+
}
93+
}
94+
},
95+
})
96+
97+
/* eslint-disable @typescript-eslint/no-namespace */
98+
declare global {
99+
namespace jest {
100+
// eslint-disable-next-line @typescript-eslint/naming-convention
101+
interface Expect {
102+
toHaveInSet(item: any): any
103+
}
104+
}
105+
}
106+
107+
describe(`query-running state machine`, () => {
108+
beforeEach(() => {
109+
resetAllMocks()
110+
})
111+
112+
it(`initialises`, async () => {
113+
const service = interpret(machine)
114+
// debug(service)
115+
116+
service.start()
117+
expect(service.state.value).toBe(`extractingQueries`)
118+
})
119+
120+
it(`doesn't drop pendingQueryRuns that were added during calculation of dirty queries`, async () => {
121+
const deferred = pDefer<{
122+
queryIds: IGroupedQueryIds
123+
}>()
124+
const waitForExecutionOfCalcDirtyQueries = pDefer()
125+
126+
services.calculateDirtyQueries.mockImplementation(
127+
async (): Promise<{
128+
queryIds: IGroupedQueryIds
129+
}> => {
130+
waitForExecutionOfCalcDirtyQueries.resolve()
131+
132+
// allow test to execute some code before resuming service
133+
134+
await deferred.promise
135+
136+
return {
137+
queryIds: {
138+
pageQueryIds: [],
139+
staticQueryIds: [],
140+
},
141+
}
142+
}
143+
)
144+
145+
const service = interpret(machine)
146+
// debug(service)
147+
148+
service.send({
149+
type: `QUERY_RUN_REQUESTED`,
150+
payload: {
151+
pagePath: `/bar/`,
152+
},
153+
})
154+
155+
service.start()
156+
157+
await waitForExecutionOfCalcDirtyQueries.promise
158+
159+
// we are in middle of execution of calcDirtyQueries service
160+
// let's dispatch QUERY_RUN_REQUESTED for page /foo/
161+
service.send({
162+
type: `QUERY_RUN_REQUESTED`,
163+
payload: {
164+
pagePath: `/foo/`,
165+
},
166+
})
167+
168+
deferred.resolve()
169+
170+
// let state machine reach final state
171+
await finished(service)
172+
173+
// let's make sure that we called calculateDirtyQueries service
174+
// with every page that was requested, even if page was requested
175+
// while we were executing calcDirtyQueries service
176+
expect(services.calculateDirtyQueries).toHaveBeenCalledWith(
177+
expect.objectContaining({
178+
currentlyHandledPendingQueryRuns: expect.toHaveInSet(`/`),
179+
}),
180+
expect.anything(),
181+
expect.anything()
182+
)
183+
184+
expect(services.calculateDirtyQueries).toHaveBeenCalledWith(
185+
expect.objectContaining({
186+
currentlyHandledPendingQueryRuns: expect.toHaveInSet(`/bar/`),
187+
}),
188+
expect.anything(),
189+
expect.anything()
190+
)
191+
192+
expect(services.calculateDirtyQueries).toHaveBeenCalledWith(
193+
expect.objectContaining({
194+
currentlyHandledPendingQueryRuns: expect.toHaveInSet(`/foo/`),
195+
}),
196+
expect.anything(),
197+
expect.anything()
198+
)
199+
})
200+
})

packages/gatsby/src/state-machines/data-layer/services.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ServiceConfig } from "xstate"
1+
import { MachineOptions } from "xstate"
22
import {
33
customizeSchema,
44
createPages,
@@ -8,10 +8,10 @@ import {
88
} from "../../services"
99
import { IDataLayerContext } from "./types"
1010

11-
export const dataLayerServices: Record<
12-
string,
13-
ServiceConfig<IDataLayerContext>
14-
> = {
11+
export const dataLayerServices: MachineOptions<
12+
IDataLayerContext,
13+
any
14+
>["services"] = {
1515
customizeSchema,
1616
sourceNodes,
1717
createPages,

packages/gatsby/src/state-machines/develop/services.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import {
1313
} from "../data-layer"
1414
import { queryRunningMachine } from "../query-running"
1515
import { waitingMachine } from "../waiting"
16-
import { ServiceConfig } from "xstate"
16+
import { MachineOptions } from "xstate"
1717

18-
export const developServices: Record<string, ServiceConfig<IBuildContext>> = {
18+
export const developServices: MachineOptions<IBuildContext, any>["services"] = {
1919
initializeData: initializeDataMachine,
2020
reloadData: reloadDataMachine,
2121
recreatePages: recreatePagesMachine,

packages/gatsby/src/state-machines/query-running/services.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ServiceConfig } from "xstate"
1+
import { MachineOptions } from "xstate"
22
import {
33
extractQueries,
44
writeOutRequires,
@@ -10,10 +10,10 @@ import {
1010
} from "../../services"
1111
import { IQueryRunningContext } from "./types"
1212

13-
export const queryRunningServices: Record<
14-
string,
15-
ServiceConfig<IQueryRunningContext>
16-
> = {
13+
export const queryRunningServices: MachineOptions<
14+
IQueryRunningContext,
15+
any
16+
>["services"] = {
1717
extractQueries,
1818
writeOutRequires,
1919
calculateDirtyQueries,

packages/gatsby/src/utils/state-machine-logging.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import {
77
} from "xstate"
88
import reporter from "gatsby-cli/lib/reporter"
99

10+
type AnyInterpreterWithContext<T> = Interpreter<T, any, any, any, any>
11+
1012
const isInterpreter = <T>(
1113
actor: Actor<T> | Interpreter<T>
1214
): actor is Interpreter<T> => `machine` in actor
1315

1416
export function logTransitions<T = DefaultContext>(
15-
service: Interpreter<T>
17+
service: AnyInterpreterWithContext<T>
1618
): void {
1719
const listeners = new WeakSet()
1820
let last: State<T, AnyEventObject, any, any>

yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -26950,10 +26950,10 @@ xss@^1.0.6:
2695026950
commander "^2.20.3"
2695126951
cssfilter "0.0.10"
2695226952

26953-
xstate@^4.26.0, xstate@^4.26.1:
26954-
version "4.26.1"
26955-
resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.26.1.tgz#4fc1afd153f88cf302a9ee2b758f6629e6a829b6"
26956-
integrity sha512-JLofAEnN26l/1vbODgsDa+Phqa61PwDlxWu8+2pK+YbXf+y9pQSDLRvcYH2H1kkeUBA5fGp+xFL/zfE8jNMw4g==
26953+
xstate@4.32.1:
26954+
version "4.32.1"
26955+
resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.32.1.tgz#1a09c808a66072938861a3b4acc5b38460244b70"
26956+
integrity sha512-QYUd+3GkXZ8i6qdixnOn28bL3EvA++LONYL/EMWwKlFSh/hiLndJ8YTnz77FDs+JUXcwU7NZJg7qoezoRHc4GQ==
2695726957

2695826958
xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
2695926959
version "4.0.2"

0 commit comments

Comments
 (0)