@quenty/marketplaceutils 11.23.0 → 11.25.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/CHANGELOG.md +12 -0
- package/deploy.nevermore.json +10 -0
- package/package.json +7 -4
- package/src/Shared/MarketplaceUtils.lua +57 -5
- package/src/Shared/MarketplaceUtils.spec.lua +215 -0
- package/src/jest.config.lua +3 -0
- package/test/default.project.json +25 -0
- package/test/scripts/Server/ServerMain.server.lua +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [11.25.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/marketplaceutils@11.24.0...@quenty/marketplaceutils@11.25.0) (2026-07-23)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- Add baseline player-mock and support across Nevermore for mocked players. ([567d121](https://github.com/Quenty/NevermoreEngine/commit/567d121ffc014b42391554088189a1a6296dda83))
|
|
11
|
+
|
|
12
|
+
# [11.24.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/marketplaceutils@11.23.0...@quenty/marketplaceutils@11.24.0) (2026-07-20)
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
- **gameproductservice:** add paid-access game ownership tracking ([581a595](https://github.com/Quenty/NevermoreEngine/commit/581a5950d433ea4d6dfbcc33e88f254f9f13e14c))
|
|
17
|
+
|
|
6
18
|
# [11.23.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/marketplaceutils@11.22.0...@quenty/marketplaceutils@11.23.0) (2026-07-18)
|
|
7
19
|
|
|
8
20
|
**Note:** Version bump only for package @quenty/marketplaceutils
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/marketplaceutils",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.25.0",
|
|
4
4
|
"description": "Provides utility methods for MarketplaceService",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -31,11 +31,14 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@quenty/loader": "10.11.0",
|
|
33
33
|
"@quenty/memoize": "1.10.0",
|
|
34
|
-
"@quenty/
|
|
35
|
-
"@quenty/
|
|
34
|
+
"@quenty/nevermore-test-runner": "1.5.0",
|
|
35
|
+
"@quenty/playermock": "1.1.0",
|
|
36
|
+
"@quenty/promise": "10.21.0",
|
|
37
|
+
"@quenty/servicebag": "11.20.0",
|
|
38
|
+
"@quentystudios/jest-lua": "3.10.0-quenty.2"
|
|
36
39
|
},
|
|
37
40
|
"publishConfig": {
|
|
38
41
|
"access": "public"
|
|
39
42
|
},
|
|
40
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "1de37218a2bedb8e3f8614a2e09bba9eddc812da"
|
|
41
44
|
}
|
|
@@ -8,6 +8,7 @@ local require = require(script.Parent.loader).load(script)
|
|
|
8
8
|
|
|
9
9
|
local MarketplaceService = game:GetService("MarketplaceService")
|
|
10
10
|
|
|
11
|
+
local PlayerMock = require("PlayerMock")
|
|
11
12
|
local Promise = require("Promise")
|
|
12
13
|
|
|
13
14
|
local MarketplaceUtils = {}
|
|
@@ -153,13 +154,18 @@ function MarketplaceUtils.promiseUserSubscriptionStatus(
|
|
|
153
154
|
player: Player,
|
|
154
155
|
subscriptionId: string
|
|
155
156
|
): Promise.Promise<UserSubscriptonStatus>
|
|
156
|
-
assert(typeof(player) == "Instance" and player:IsA("Player"), "Bad player")
|
|
157
|
+
assert(typeof(player) == "Instance" and (player:IsA("Player") or PlayerMock.isMock(player)), "Bad player")
|
|
157
158
|
assert(type(subscriptionId) == "string", "Bad subscriptionId")
|
|
158
159
|
|
|
159
160
|
return Promise.spawn(function(resolve, reject)
|
|
160
161
|
local subStatus
|
|
161
162
|
local ok, err = pcall(function()
|
|
162
|
-
|
|
163
|
+
if PlayerMock.isMock(player) then
|
|
164
|
+
subStatus =
|
|
165
|
+
PlayerMock.readLookup(player, "MarketplaceService.GetUserSubscriptionStatusAsync", subscriptionId)
|
|
166
|
+
else
|
|
167
|
+
subStatus = MarketplaceService:GetUserSubscriptionStatusAsync(player, subscriptionId)
|
|
168
|
+
end
|
|
163
169
|
end)
|
|
164
170
|
if not ok then
|
|
165
171
|
return reject(err)
|
|
@@ -184,7 +190,12 @@ function MarketplaceUtils.promiseUserOwnsGamePass(userId: number, gamePassId: nu
|
|
|
184
190
|
return Promise.spawn(function(resolve, reject)
|
|
185
191
|
local result
|
|
186
192
|
local ok, err = pcall(function()
|
|
187
|
-
|
|
193
|
+
local mockPlayer = PlayerMock.getMockByUserId(userId)
|
|
194
|
+
if mockPlayer ~= nil then
|
|
195
|
+
result = PlayerMock.readLookup(mockPlayer, "MarketplaceService.UserOwnsGamePassAsync", gamePassId)
|
|
196
|
+
else
|
|
197
|
+
result = MarketplaceService:UserOwnsGamePassAsync(userId, gamePassId)
|
|
198
|
+
end
|
|
188
199
|
end)
|
|
189
200
|
if not ok then
|
|
190
201
|
return reject(err)
|
|
@@ -209,7 +220,44 @@ function MarketplaceUtils.promisePlayerOwnsAsset(player: Player, assetId: number
|
|
|
209
220
|
return Promise.spawn(function(resolve, reject)
|
|
210
221
|
local result
|
|
211
222
|
local ok, err = pcall(function()
|
|
212
|
-
|
|
223
|
+
if PlayerMock.isMock(player) then
|
|
224
|
+
result = PlayerMock.readLookup(player, "MarketplaceService.PlayerOwnsAsset", assetId)
|
|
225
|
+
else
|
|
226
|
+
result = MarketplaceService:PlayerOwnsAsset(player, assetId)
|
|
227
|
+
end
|
|
228
|
+
end)
|
|
229
|
+
if not ok then
|
|
230
|
+
return reject(err)
|
|
231
|
+
end
|
|
232
|
+
if type(result) ~= "boolean" then
|
|
233
|
+
return reject("Bad result type")
|
|
234
|
+
end
|
|
235
|
+
return resolve(result)
|
|
236
|
+
end)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
--[=[
|
|
240
|
+
Retrieves whether a player owns an asset via the async variant. Unlike
|
|
241
|
+
[MarketplaceUtils.promisePlayerOwnsAsset], this queries whether the player owns
|
|
242
|
+
paid access to a game (universe), which is the mechanism paid-access games use.
|
|
243
|
+
See [MarketplaceService.PlayerOwnsAssetAsync].
|
|
244
|
+
|
|
245
|
+
@param player Player
|
|
246
|
+
@param assetId number
|
|
247
|
+
@return Promise<boolean>
|
|
248
|
+
]=]
|
|
249
|
+
function MarketplaceUtils.promisePlayerOwnsAssetAsync(player: Player, assetId: number): Promise.Promise<boolean>
|
|
250
|
+
assert(typeof(player) == "Instance", "Bad player")
|
|
251
|
+
assert(type(assetId) == "number", "Bad assetId")
|
|
252
|
+
|
|
253
|
+
return Promise.spawn(function(resolve, reject)
|
|
254
|
+
local result
|
|
255
|
+
local ok, err = pcall(function()
|
|
256
|
+
if PlayerMock.isMock(player) then
|
|
257
|
+
result = PlayerMock.readLookup(player, "MarketplaceService.PlayerOwnsAssetAsync", assetId)
|
|
258
|
+
else
|
|
259
|
+
result = MarketplaceService:PlayerOwnsAssetAsync(player, assetId)
|
|
260
|
+
end
|
|
213
261
|
end)
|
|
214
262
|
if not ok then
|
|
215
263
|
return reject(err)
|
|
@@ -234,7 +282,11 @@ function MarketplaceUtils.promisePlayerOwnsBundle(player: Player, bundleId: numb
|
|
|
234
282
|
return Promise.spawn(function(resolve, reject)
|
|
235
283
|
local result
|
|
236
284
|
local ok, err = pcall(function()
|
|
237
|
-
|
|
285
|
+
if PlayerMock.isMock(player) then
|
|
286
|
+
result = PlayerMock.readLookup(player, "MarketplaceService.PlayerOwnsBundle", bundleId)
|
|
287
|
+
else
|
|
288
|
+
result = MarketplaceService:PlayerOwnsBundle(player, bundleId)
|
|
289
|
+
end
|
|
238
290
|
end)
|
|
239
291
|
if not ok then
|
|
240
292
|
return reject(err)
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--[[
|
|
3
|
+
@class MarketplaceUtils.spec.lua
|
|
4
|
+
]]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local Workspace = game:GetService("Workspace")
|
|
9
|
+
|
|
10
|
+
local Jest = require("Jest")
|
|
11
|
+
local MarketplaceServiceCache = require("MarketplaceServiceCache")
|
|
12
|
+
local MarketplaceUtils = require("MarketplaceUtils")
|
|
13
|
+
local PlayerMock = require("PlayerMock")
|
|
14
|
+
local PromiseTestUtils = require("PromiseTestUtils")
|
|
15
|
+
|
|
16
|
+
local afterEach = Jest.Globals.afterEach
|
|
17
|
+
local describe = Jest.Globals.describe
|
|
18
|
+
local expect = Jest.Globals.expect
|
|
19
|
+
local it = Jest.Globals.it
|
|
20
|
+
|
|
21
|
+
local MOCK_USER_ID = 88771001
|
|
22
|
+
local GAME_PASS_ID = 111222333
|
|
23
|
+
local ASSET_ID = 444555666
|
|
24
|
+
local BUNDLE_ID = 777888999
|
|
25
|
+
local SUBSCRIPTION_ID = "EXP-88771001"
|
|
26
|
+
|
|
27
|
+
local createdMocks: { Player } = {}
|
|
28
|
+
|
|
29
|
+
local function makeMock(overrides: { [string]: any }?): Player
|
|
30
|
+
local player = PlayerMock.new(overrides)
|
|
31
|
+
player.Parent = Workspace
|
|
32
|
+
table.insert(createdMocks, player)
|
|
33
|
+
return player
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
local function awaitBool(promise: any): boolean
|
|
37
|
+
expect(PromiseTestUtils.awaitSettled(promise, 5)).toBe(true)
|
|
38
|
+
local ok, value = promise:Yield()
|
|
39
|
+
expect(ok).toBe(true)
|
|
40
|
+
return value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
afterEach(function()
|
|
44
|
+
for _, player in createdMocks do
|
|
45
|
+
player:Destroy()
|
|
46
|
+
end
|
|
47
|
+
table.clear(createdMocks)
|
|
48
|
+
end)
|
|
49
|
+
|
|
50
|
+
describe("MarketplaceUtils.promiseUserOwnsGamePass", function()
|
|
51
|
+
it("resolves false for a mock's userId with no injected ownership", function()
|
|
52
|
+
makeMock({ UserId = MOCK_USER_ID })
|
|
53
|
+
|
|
54
|
+
expect(awaitBool(MarketplaceUtils.promiseUserOwnsGamePass(MOCK_USER_ID, GAME_PASS_ID))).toBe(false)
|
|
55
|
+
end)
|
|
56
|
+
|
|
57
|
+
it("resolves the ownership injected on the mock", function()
|
|
58
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
59
|
+
PlayerMock.writeLookup(player, "MarketplaceService.UserOwnsGamePassAsync", GAME_PASS_ID, true)
|
|
60
|
+
|
|
61
|
+
expect(awaitBool(MarketplaceUtils.promiseUserOwnsGamePass(MOCK_USER_ID, GAME_PASS_ID))).toBe(true)
|
|
62
|
+
end)
|
|
63
|
+
|
|
64
|
+
it("keys the injected ownership by gamePassId", function()
|
|
65
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
66
|
+
PlayerMock.writeLookup(player, "MarketplaceService.UserOwnsGamePassAsync", GAME_PASS_ID, true)
|
|
67
|
+
|
|
68
|
+
expect(awaitBool(MarketplaceUtils.promiseUserOwnsGamePass(MOCK_USER_ID, GAME_PASS_ID + 1))).toBe(false)
|
|
69
|
+
end)
|
|
70
|
+
|
|
71
|
+
it("clears back to false when the injection is cleared", function()
|
|
72
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
73
|
+
PlayerMock.writeLookup(player, "MarketplaceService.UserOwnsGamePassAsync", GAME_PASS_ID, true)
|
|
74
|
+
PlayerMock.writeLookup(player, "MarketplaceService.UserOwnsGamePassAsync", GAME_PASS_ID, nil)
|
|
75
|
+
|
|
76
|
+
expect(awaitBool(MarketplaceUtils.promiseUserOwnsGamePass(MOCK_USER_ID, GAME_PASS_ID))).toBe(false)
|
|
77
|
+
end)
|
|
78
|
+
|
|
79
|
+
it("asserts on a non-number userId", function()
|
|
80
|
+
expect(function()
|
|
81
|
+
MarketplaceUtils.promiseUserOwnsGamePass("nope" :: any, GAME_PASS_ID)
|
|
82
|
+
end).toThrow()
|
|
83
|
+
end)
|
|
84
|
+
end)
|
|
85
|
+
|
|
86
|
+
describe("MarketplaceUtils.promisePlayerOwnsAsset", function()
|
|
87
|
+
it("resolves false for a mock with no injected ownership", function()
|
|
88
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
89
|
+
|
|
90
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsAsset(player, ASSET_ID))).toBe(false)
|
|
91
|
+
end)
|
|
92
|
+
|
|
93
|
+
it("resolves the ownership injected on the mock", function()
|
|
94
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
95
|
+
PlayerMock.writeLookup(player, "MarketplaceService.PlayerOwnsAsset", ASSET_ID, true)
|
|
96
|
+
|
|
97
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsAsset(player, ASSET_ID))).toBe(true)
|
|
98
|
+
end)
|
|
99
|
+
end)
|
|
100
|
+
|
|
101
|
+
describe("MarketplaceUtils.promisePlayerOwnsAssetAsync", function()
|
|
102
|
+
it("resolves false for a mock with no injected ownership", function()
|
|
103
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
104
|
+
|
|
105
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsAssetAsync(player, ASSET_ID))).toBe(false)
|
|
106
|
+
end)
|
|
107
|
+
|
|
108
|
+
it("resolves the ownership injected on the mock", function()
|
|
109
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
110
|
+
PlayerMock.writeLookup(player, "MarketplaceService.PlayerOwnsAssetAsync", ASSET_ID, true)
|
|
111
|
+
|
|
112
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsAssetAsync(player, ASSET_ID))).toBe(true)
|
|
113
|
+
end)
|
|
114
|
+
|
|
115
|
+
it("reads a distinct domain from promisePlayerOwnsAsset", function()
|
|
116
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
117
|
+
PlayerMock.writeLookup(player, "MarketplaceService.PlayerOwnsAsset", ASSET_ID, true)
|
|
118
|
+
|
|
119
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsAssetAsync(player, ASSET_ID))).toBe(false)
|
|
120
|
+
end)
|
|
121
|
+
end)
|
|
122
|
+
|
|
123
|
+
describe("MarketplaceUtils.promisePlayerOwnsBundle", function()
|
|
124
|
+
it("resolves false for a mock with no injected ownership", function()
|
|
125
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
126
|
+
|
|
127
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsBundle(player, BUNDLE_ID))).toBe(false)
|
|
128
|
+
end)
|
|
129
|
+
|
|
130
|
+
it("resolves the ownership injected on the mock", function()
|
|
131
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
132
|
+
PlayerMock.writeLookup(player, "MarketplaceService.PlayerOwnsBundle", BUNDLE_ID, true)
|
|
133
|
+
|
|
134
|
+
expect(awaitBool(MarketplaceUtils.promisePlayerOwnsBundle(player, BUNDLE_ID))).toBe(true)
|
|
135
|
+
end)
|
|
136
|
+
end)
|
|
137
|
+
|
|
138
|
+
describe("MarketplaceUtils.promiseUserSubscriptionStatus", function()
|
|
139
|
+
it("resolves an unsubscribed status for a mock with no injected status", function()
|
|
140
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
141
|
+
|
|
142
|
+
local outcome, status =
|
|
143
|
+
PromiseTestUtils.awaitOutcome(MarketplaceUtils.promiseUserSubscriptionStatus(player, SUBSCRIPTION_ID))
|
|
144
|
+
expect(outcome).toBe("resolved")
|
|
145
|
+
expect(status.IsSubscribed).toBe(false)
|
|
146
|
+
expect(status.IsRenewing).toBe(false)
|
|
147
|
+
end)
|
|
148
|
+
|
|
149
|
+
it("resolves the status injected on the mock", function()
|
|
150
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
151
|
+
PlayerMock.writeLookup(player, "MarketplaceService.GetUserSubscriptionStatusAsync", SUBSCRIPTION_ID, {
|
|
152
|
+
IsSubscribed = true,
|
|
153
|
+
IsRenewing = true,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
local outcome, status =
|
|
157
|
+
PromiseTestUtils.awaitOutcome(MarketplaceUtils.promiseUserSubscriptionStatus(player, SUBSCRIPTION_ID))
|
|
158
|
+
expect(outcome).toBe("resolved")
|
|
159
|
+
expect(status.IsSubscribed).toBe(true)
|
|
160
|
+
expect(status.IsRenewing).toBe(true)
|
|
161
|
+
end)
|
|
162
|
+
|
|
163
|
+
it("keys the injected status by subscriptionId", function()
|
|
164
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
165
|
+
PlayerMock.writeLookup(player, "MarketplaceService.GetUserSubscriptionStatusAsync", SUBSCRIPTION_ID, {
|
|
166
|
+
IsSubscribed = true,
|
|
167
|
+
IsRenewing = false,
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
local outcome, status =
|
|
171
|
+
PromiseTestUtils.awaitOutcome(MarketplaceUtils.promiseUserSubscriptionStatus(player, "EXP-other"))
|
|
172
|
+
expect(outcome).toBe("resolved")
|
|
173
|
+
expect(status.IsSubscribed).toBe(false)
|
|
174
|
+
end)
|
|
175
|
+
|
|
176
|
+
it("asserts on a non-player value", function()
|
|
177
|
+
expect(function()
|
|
178
|
+
MarketplaceUtils.promiseUserSubscriptionStatus(Instance.new("Folder") :: any, SUBSCRIPTION_ID)
|
|
179
|
+
end).toThrow("Bad player")
|
|
180
|
+
end)
|
|
181
|
+
|
|
182
|
+
it("asserts on a non-string subscriptionId", function()
|
|
183
|
+
local player = makeMock({ UserId = MOCK_USER_ID })
|
|
184
|
+
|
|
185
|
+
expect(function()
|
|
186
|
+
MarketplaceUtils.promiseUserSubscriptionStatus(player, 123 :: any)
|
|
187
|
+
end).toThrow("Bad subscriptionId")
|
|
188
|
+
end)
|
|
189
|
+
end)
|
|
190
|
+
|
|
191
|
+
describe("MarketplaceUtils.promiseProductInfo", function()
|
|
192
|
+
it("asserts on a non-number assetId", function()
|
|
193
|
+
expect(function()
|
|
194
|
+
MarketplaceUtils.promiseProductInfo("nope" :: any, Enum.InfoType.GamePass)
|
|
195
|
+
end).toThrow("Bad assetId")
|
|
196
|
+
end)
|
|
197
|
+
|
|
198
|
+
it("asserts on a non-EnumItem infoType", function()
|
|
199
|
+
expect(function()
|
|
200
|
+
MarketplaceUtils.promiseProductInfo(ASSET_ID, 5 :: any)
|
|
201
|
+
end).toThrow("Bad infoType")
|
|
202
|
+
end)
|
|
203
|
+
end)
|
|
204
|
+
|
|
205
|
+
describe("MarketplaceServiceCache.PromiseProductInfo", function()
|
|
206
|
+
it("asserts on a non-number productId", function()
|
|
207
|
+
expect(function()
|
|
208
|
+
MarketplaceServiceCache.PromiseProductInfo(
|
|
209
|
+
MarketplaceServiceCache :: any,
|
|
210
|
+
"nope" :: any,
|
|
211
|
+
Enum.InfoType.Asset
|
|
212
|
+
)
|
|
213
|
+
end).toThrow("Bad productId")
|
|
214
|
+
end)
|
|
215
|
+
end)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "MarketplaceUtilsTest",
|
|
3
|
+
"globIgnorePaths": [
|
|
4
|
+
"**/.package-lock.json",
|
|
5
|
+
"**/.pnpm",
|
|
6
|
+
"**/.pnpm-workspace-state-v1.json",
|
|
7
|
+
"**/.modules.yaml",
|
|
8
|
+
"**/.ignored",
|
|
9
|
+
"**/.ignored_*"
|
|
10
|
+
],
|
|
11
|
+
"tree": {
|
|
12
|
+
"$className": "DataModel",
|
|
13
|
+
"ServerScriptService": {
|
|
14
|
+
"$properties": {
|
|
15
|
+
"LoadStringEnabled": true
|
|
16
|
+
},
|
|
17
|
+
"marketplaceutils": {
|
|
18
|
+
"$path": ".."
|
|
19
|
+
},
|
|
20
|
+
"Script": {
|
|
21
|
+
"$path": "scripts/Server"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
--[[
|
|
2
|
+
@class ServerMain
|
|
3
|
+
]]
|
|
4
|
+
local ServerScriptService = game:GetService("ServerScriptService")
|
|
5
|
+
|
|
6
|
+
local root = ServerScriptService.marketplaceutils
|
|
7
|
+
local loader = root:FindFirstChild("LoaderUtils", true).Parent
|
|
8
|
+
local require = require(loader).bootstrapGame(root)
|
|
9
|
+
|
|
10
|
+
local NevermoreTestRunnerUtils = require("NevermoreTestRunnerUtils")
|
|
11
|
+
if NevermoreTestRunnerUtils.runTestsIfNeededAsync(root) then
|
|
12
|
+
return
|
|
13
|
+
end
|