This commit is contained in:
lx
2026-07-06 14:01:11 -04:00
commit c4f97d729d
16468 changed files with 935321 additions and 0 deletions
@@ -0,0 +1,22 @@
-- main AppShell reducer
local Reducers = script.Parent
local RobloxUser = require(Reducers.RobloxUser)
local ScreenList = require(Reducers.ScreenList)
local XboxUser = require(Reducers.XboxUser)
local UserThumbnails = require(Reducers.UserThumbnails)
local Friends = require(Reducers.Friends)
local RenderedFriends = require(Reducers.RenderedFriends)
return function(state, action)
state = state or {}
return {
-- Use reducer composition to add reducers here
RobloxUser = RobloxUser(state.RobloxUser, action),
ScreenList = ScreenList(state.ScreenList, action),
XboxUser = XboxUser(state.XboxUser, action),
UserThumbnails = UserThumbnails(state.UserThumbnails, action),
Friends = Friends(state.Friends, action),
RenderedFriends = RenderedFriends(state.RenderedFriends, action),
}
end
@@ -0,0 +1,10 @@
return function()
local AppShellReducer = require(script.Parent.AppShellReducer)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = AppShellReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
end
@@ -0,0 +1,32 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local Immutable = require(Modules.Common.Immutable)
local RequestCrossPlayEnabled = require(Modules.Shell.Actions.RequestCrossPlayEnabled)
local SetCrossPlayEnabled = require(Modules.Shell.Actions.SetCrossPlayEnabled)
local PostCrossPlayEnabledFailed = require(Modules.Shell.Actions.PostCrossPlayEnabledFailed)
local GetCrossPlayEnabledFailed = require(Modules.Shell.Actions.GetCrossPlayEnabledFailed)
--To use: Add CrossPlayEnabledState = CrossPlayEnabledState(state.CrossPlayEnabledState, action) to the AppShellReducer
return function(state, action)
state = state or {}
if action.type == RequestCrossPlayEnabled.name then
state = Immutable.Set(state, "isRequesting", true)
elseif action.type == SetCrossPlayEnabled.name then
if action.enabled ~= nil then
state =
{
enabled = action.enabled,
lastUpdated = action.timestamp,
isRequesting = false,
}
else
state = {}
end
elseif action.type == PostCrossPlayEnabledFailed.name then
state = Immutable.Set(state, "isRequesting", false)
elseif action.type == GetCrossPlayEnabledFailed.name then
state = Immutable.Set(state, "isRequesting", false)
end
return state
end
@@ -0,0 +1,71 @@
return function()
local CrossPlayEnabledStateReducer = require(script.Parent.CrossPlayEnabledState)
local Actions = script.Parent.Parent.Actions
local RequestCrossPlayEnabled = require(Actions.RequestCrossPlayEnabled)
local SetCrossPlayEnabled = require(Actions.SetCrossPlayEnabled)
local PostCrossPlayEnabledFailed = require(Actions.PostCrossPlayEnabledFailed)
local GetCrossPlayEnabledFailed = require(Actions.GetCrossPlayEnabledFailed)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = CrossPlayEnabledStateReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action RequestCrossPlayEnabled", function()
it("should set isRequesting to true in the store", function()
local action = RequestCrossPlayEnabled()
local state = CrossPlayEnabledStateReducer({}, action)
expect(state).to.be.a("table")
expect(state.isRequesting).to.equal(true)
end)
end)
describe("Action SetCrossPlayEnabled", function()
it("should set enabled, lastUpdated and reset isRequesting to false in the store", function()
local action = SetCrossPlayEnabled(true, tick())
local state = CrossPlayEnabledStateReducer({}, action)
expect(state).to.be.a("table")
expect(state.enabled).to.equal(true)
expect(state.lastUpdated).to.be.a("number")
expect(state.isRequesting).to.equal(false)
end)
it("should clear enabled, lastUpdated to nil and reset isRequesting to nil when SetCrossPlayEnabled with nil", function()
local action = SetCrossPlayEnabled(true, tick())
local state = CrossPlayEnabledStateReducer({}, action)
action = SetCrossPlayEnabled()
state = CrossPlayEnabledStateReducer(state, action)
expect(state).to.be.a("table")
expect(state.enabled).never.to.be.ok()
expect(state.lastUpdated).never.to.be.ok()
expect(state.isRequesting).never.to.be.ok()
end)
end)
describe("Action PostCrossPlayEnabledFailed", function()
it("should set isRequesting to false in the store", function()
local action = PostCrossPlayEnabledFailed()
local state = CrossPlayEnabledStateReducer({}, action)
expect(state).to.be.a("table")
expect(state.isRequesting).to.equal(false)
end)
end)
describe("Action GetCrossPlayEnabledFailed", function()
it("should set isRequesting to false in the store", function()
local action = GetCrossPlayEnabledFailed()
local state = CrossPlayEnabledStateReducer({}, action)
expect(state).to.be.a("table")
expect(state.isRequesting).to.equal(false)
end)
end)
end
@@ -0,0 +1,26 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local OrderedMap = require(Modules.Shell.OrderedMap)
local DeleteError = require(Modules.Shell.Actions.DeleteError)
local function getErrorCode(error)
return error.Code
end
local function errorSortPredicate(error1, error2)
return error1.timestamp < error2.timestamp
end
return function(state, action)
state = state or OrderedMap.new(getErrorCode, errorSortPredicate)
--OrderedMap.Delete and OrderedMap.Insert are immutable operations and a new table is returned.
if action.error and type(getErrorCode(action.error)) == "number" then
if action.type == DeleteError.name then
state = OrderedMap.Delete(state, getErrorCode(action.error))
else
state = OrderedMap.Insert(state, action.error)
end
end
return state
end
@@ -0,0 +1,45 @@
return function()
local ErrorHandler = require(script.Parent.ErrorHandler)
local Actions = script.Parent.Parent.Actions
local AddError = require(Actions.AddError)
local DeleteError = require(Actions.DeleteError)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = ErrorHandler(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action AddError", function()
it("should add the error to the errormap when an action with error dispatched", function()
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local ShellModules = Modules:FindFirstChild("Shell")
local Errors = require(ShellModules:FindFirstChild('Errors'))
local DefaultError = Errors.Default
local action = AddError(DefaultError, tick())
local state = ErrorHandler(nil, action)
expect(state).to.be.a("table")
expect(state:Length()).to.equal(1)
expect(state:First()).to.equal(action.error)
end)
end)
describe("Action DeleteError", function()
it("should delete the corresponding error in the errormap when DeleteError", function()
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local ShellModules = Modules:FindFirstChild("Shell")
local Errors = require(ShellModules:FindFirstChild('Errors'))
local DefaultError = Errors.Default
local action = AddError(DefaultError, tick())
local state = ErrorHandler(nil, action)
action = DeleteError(action.error)
state = ErrorHandler(state, action)
expect(state).to.be.a("table")
expect(state:Length()).to.equal(0)
end)
end)
end
@@ -0,0 +1,49 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local SetFriendsData = require(Modules.Shell.Actions.SetFriendsData)
local Immutable = require(Modules.Common.Immutable)
--[[
// action is table
// Table keys:
// [index number] - table
// xuid - number
// robloxName - string
// placeId - number
// robloxStatus - string
// robloxuid - number
// lastLocation - string
// gamertag - string
// xboxStatus - string
// friendsSource - string
]]
return function(state, action)
state = state or {
initialized = false,
data = {}
}
if action.type == SetFriendsData.name then
-- Use nil in setFriendsData to reset
if not action.data then
return {
initialized = false,
data = {}
}
end
-- Make a copy of new friends
local newFriendsData = {}
for i in ipairs(action.data) do
local friendDataTable = Immutable.JoinDictionaries(action.data[i])
table.insert(newFriendsData, friendDataTable)
end
return {
initialized = true,
data = newFriendsData
}
end
return state
end
@@ -0,0 +1,65 @@
return function()
local FriendsReducer = require(script.Parent.Friends)
local Actions = script.Parent.Parent.Actions
local SetFriendsData = require(Actions.SetFriendsData)
describe("initial state", function()
it("should return an table when passed nil", function()
local state = FriendsReducer(nil, {})
expect(state).to.be.a("table")
end)
it("should set initial values when passed nil", function()
local state = FriendsReducer(nil, {})
expect(state.initialized).to.be.a("boolean")
expect(state.initialized).to.equal(false)
expect(state.data).to.be.a("table")
expect(#state.data).to.equal(0)
end)
end)
describe("Action SetFriendsData", function()
it("should initialize friends in data", function()
local action = SetFriendsData({ {}, {} })
local state = FriendsReducer(nil, action)
expect(state.data).to.be.a("table")
expect(state.data[2]).to.be.a("table")
expect(state.initialized).to.equal(true)
end)
it("should put friend data into the entries", function()
local action = SetFriendsData({ { xuid=12345, robloxName="TestName", xboxStatus="online" } })
local state = FriendsReducer(nil, action)
expect(state.data[1].xuid).to.be.a("number")
expect(state.data[1].xuid).to.equal(12345)
expect(state.data[1].robloxName).to.be.a("string")
expect(state.data[1].robloxName).to.equal("TestName")
end)
it("should clear the friends array when passed an empty table", function()
local action = SetFriendsData({ { xuid=12345, robloxName="TestName", xboxStatus="online" } })
local state = FriendsReducer(nil, action)
action = SetFriendsData({})
state = FriendsReducer(state, action)
expect(state.data).to.be.a("table")
expect(#state.data).to.equal(0)
end)
it("should reset the state when passed a nil SetFriendsData action", function()
local action = SetFriendsData({ { xuid=12345, robloxName="TestName", xboxStatus="online" } })
local state = FriendsReducer(nil, action)
action = SetFriendsData(nil)
state = FriendsReducer(state, action)
expect(state.initialized).to.be.a("boolean")
expect(state.initialized).to.equal(false)
expect(state.data).to.be.a("table")
expect(#state.data).to.equal(0)
end)
end)
end
@@ -0,0 +1,26 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local Immutable = require(Modules.Common.Immutable)
local FetchPrivilegeSettings = require(Modules.Shell.Actions.FetchPrivilegeSettings)
local SetPrivilegeSettings = require(Modules.Shell.Actions.SetPrivilegeSettings)
return function(state, action)
state = state or {}
if action.type == FetchPrivilegeSettings.name then
state = Immutable.Set(state, "isRequesting", true)
elseif action.type == SetPrivilegeSettings.name then
if action.Multiplayer and action.SharedContent then
local multiplayerSetting = state.Multiplayer or {}
local sharedContentSetting = state.SharedContent or {}
state = {
Multiplayer = Immutable.JoinDictionaries(multiplayerSetting, action.Multiplayer),
SharedContent = Immutable.JoinDictionaries(sharedContentSetting, action.SharedContent),
lastUpdated = action.timestamp,
isRequesting = false
}
else
state = {}
end
end
return state
end
@@ -0,0 +1,51 @@
return function()
local PrivilegeSettingsStateReducer = require(script.Parent.PrivilegeSettingsState)
local Actions = script.Parent.Parent.Actions
local FetchPrivilegeSettings = require(Actions.FetchPrivilegeSettings)
local SetPrivilegeSettings = require(Actions.SetPrivilegeSettings)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = PrivilegeSettingsStateReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action FetchPrivilegeSettings", function()
it("should set isRequesting to true in the store", function()
local action = FetchPrivilegeSettings()
local state = PrivilegeSettingsStateReducer({}, action)
expect(state).to.be.a("table")
expect(state.isRequesting).to.equal(true)
end)
end)
describe("Action SetPrivilegeSettings", function()
it("should set privilege settings, lastUpdated and reset isRequesting to false in the store", function()
local action = SetPrivilegeSettings({Multiplayer = {}, SharedContent = {}, timestamp = tick()})
local state = PrivilegeSettingsStateReducer({}, action)
expect(state).to.be.a("table")
expect(state.Multiplayer).to.be.a("table")
expect(state.SharedContent).to.be.a("table")
expect(state.lastUpdated).to.be.a("number")
expect(state.isRequesting).to.equal(false)
end)
it("should set privilege settings, lastUpdated to nil and reset isRequesting to nil when SetPrivilegeSettings with nil", function()
local action = SetPrivilegeSettings({Multiplayer = {}, SharedContent = {}, timestamp = tick()})
local state = PrivilegeSettingsStateReducer({}, action)
action = SetPrivilegeSettings()
state = PrivilegeSettingsStateReducer(state, action)
expect(state).to.be.a("table")
expect(state.Multiplayer).never.to.be.ok()
expect(state.SharedContent).never.to.be.ok()
expect(state.lastUpdated).never.to.be.ok()
expect(state.isRequesting).never.to.be.ok()
end)
end)
end
@@ -0,0 +1,49 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local SetRenderedFriendsData = require(Modules.Shell.Actions.SetRenderedFriendsData)
local Immutable = require(Modules.Common.Immutable)
--[[
// action is table
// Table keys:
// [index number] - table
// xuid - number
// robloxName - string
// placeId - number
// robloxStatus - string
// robloxuid - number
// lastLocation - string
// gamertag - string
// xboxStatus - string
// friendsSource - string
]]
return function(state, action)
state = state or {
initialized = false,
data = {}
}
if action.type == SetRenderedFriendsData.name then
-- Use nil in setFriendsData to reset
if not action.data then
return {
initialized = false,
data = {}
}
end
-- Make a copy of new friends
local newFriendsData = {}
for i in ipairs(action.data) do
local friendDataTable = Immutable.JoinDictionaries(action.data[i])
table.insert(newFriendsData, friendDataTable)
end
return {
initialized = true,
data = newFriendsData
}
end
return state
end
@@ -0,0 +1,65 @@
return function()
local RenderedFriendsReducer = require(script.Parent.RenderedFriends)
local Actions = script.Parent.Parent.Actions
local SetRenderedFriendsData = require(Actions.SetRenderedFriendsData)
describe("initial state", function()
it("should return an table when passed nil", function()
local state = RenderedFriendsReducer(nil, {})
expect(state).to.be.a("table")
end)
it("should set initial values when passed nil", function()
local state = RenderedFriendsReducer(nil, {})
expect(state.initialized).to.be.a("boolean")
expect(state.initialized).to.equal(false)
expect(state.data).to.be.a("table")
expect(#state.data).to.equal(0)
end)
end)
describe("Action SetRenderedFriendsData", function()
it("should initialize friends in data", function()
local action = SetRenderedFriendsData({ {}, {} })
local state = RenderedFriendsReducer(nil, action)
expect(state.data).to.be.a("table")
expect(state.data[2]).to.be.a("table")
expect(state.initialized).to.equal(true)
end)
it("should put friend data into the entries", function()
local action = SetRenderedFriendsData({ { xuid=12345, robloxName="TestName", xboxStatus="online" } })
local state = RenderedFriendsReducer(nil, action)
expect(state.data[1].xuid).to.be.a("number")
expect(state.data[1].xuid).to.equal(12345)
expect(state.data[1].robloxName).to.be.a("string")
expect(state.data[1].robloxName).to.equal("TestName")
end)
it("should clear the friends array when passed an empty table", function()
local action = SetRenderedFriendsData({ { xuid=12345, robloxName="TestName", xboxStatus="online" } })
local state = RenderedFriendsReducer(nil, action)
action = SetRenderedFriendsData({})
state = RenderedFriendsReducer(state, action)
expect(state.data).to.be.a("table")
expect(#state.data).to.equal(0)
end)
it("should reset the state when passed a nil SetRenderedFriendsData action", function()
local action = SetRenderedFriendsData({ { xuid=12345, robloxName="TestName", xboxStatus="online" } })
local state = RenderedFriendsReducer(nil, action)
action = SetRenderedFriendsData(nil)
state = RenderedFriendsReducer(state, action)
expect(state.initialized).to.be.a("boolean")
expect(state.initialized).to.equal(false)
expect(state.data).to.be.a("table")
expect(#state.data).to.equal(0)
end)
end)
end
@@ -0,0 +1,16 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local SetRobloxUser = require(Modules.Shell.Actions.SetRobloxUser)
return function(state, action)
state = state or {}
if action.type == SetRobloxUser.name then
return {
robloxName = action.robloxName,
rbxuid = action.rbxuid,
under13 = action.under13
}
end
return state
end
@@ -0,0 +1,41 @@
return function()
local RobloxUserReducer = require(script.Parent.RobloxUser)
local Actions = script.Parent.Parent.Actions
local SetRobloxUser = require(Actions.SetRobloxUser)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = RobloxUserReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action SetRobloxUser", function()
it("should set the robloxName, rbxuid, and under13 values in the store", function()
local action = SetRobloxUser({robloxName = "TestRobloxName", rbxuid = 12345, under13 = true})
local state = RobloxUserReducer(state, action)
expect(state).to.be.a("table")
expect(state.robloxName).to.be.a("string")
expect(state.robloxName).to.equal("TestRobloxName")
expect(state.rbxuid).to.be.a("number")
expect(state.rbxuid).to.equal(12345)
expect(state.under13).to.be.a("boolean")
expect(state.under13).to.equal(true)
end)
it("should clear the robloxName, rbxuid, and under13 to nil when passed an empty SetRobloxUser action", function()
local action = SetRobloxUser({robloxName = "TestRobloxName", rbxuid = 12345, under13 = true})
local state = RobloxUserReducer(state, action)
action = SetRobloxUser({})
local state = RobloxUserReducer(state, action)
expect(state).to.be.a("table")
expect(state.robloxName).to.equal(nil)
expect(state.rbxuid).to.equal(nil)
expect(state.under13).to.equal(nil)
end)
end)
end
@@ -0,0 +1,30 @@
local CoreGui = game:GetService("CoreGui")
local Actions = CoreGui.RobloxGui.Modules.Shell.Actions
local Common = CoreGui.RobloxGui.Modules.Common
local InsertScreen = require(Actions.InsertScreen)
local RemoveScreen = require(Actions.RemoveScreen)
local Immutable = require(Common.Immutable)
return function(state, action)
state = state or {}
if action.type == InsertScreen.name then
local newList = Immutable.Append(state, action.item)
table.sort(newList, function(item1, item2)
if item1.priority == item2.priority then
return item1.createdAt > item2.createdAt
end
return item1.priority > item2.priority
end)
return newList
elseif action.type == RemoveScreen.name then
return Immutable.RemoveValueFromList(state, action.item)
end
return state
end
@@ -0,0 +1,72 @@
return function()
local ScreenList = require(script.Parent.ScreenList)
local ScreenItem = require(script.Parent.Parent.Models.ScreenItem)
local InsertScreen = require(script.Parent.Parent.Actions.InsertScreen)
local RemoveScreen = require(script.Parent.Parent.Actions.RemoveScreen)
describe("require", function()
it("should require without error", function()
require(script.Parent.ScreenList)
end)
end)
describe("call", function()
it("should create with initial state", function()
local state = ScreenList(nil, {})
expect(state).to.be.a("table")
end)
it("should insert a single screen", function()
local item = ScreenItem.new("foo", 1, {})
local action = InsertScreen(item)
local state = ScreenList({}, action)
expect(#state).to.equal(1)
expect(state[1].id).to.equal("foo")
expect(state[1].priority).to.equal(1)
expect(state[1].data).to.be.a("table")
end)
it("should insert multiple screens", function()
local item1 = ScreenItem.new("foo", 1, {})
local item2 = ScreenItem.new("bar", 2, {})
local action1 = InsertScreen(item1)
local action2 = InsertScreen(item2)
local state = ScreenList({}, action1)
state = ScreenList(state, action2)
expect(#state).to.equal(2)
expect(state[1].id).to.equal("bar")
expect(state[1].priority).to.equal(2)
expect(state[1].data).to.be.a("table")
end)
it("should sort the screens by descending priority", function()
local item1 = ScreenItem.new("foo", 3, {})
local item2 = ScreenItem.new("bar", 1, {})
local action1 = InsertScreen(item1)
local action2 = InsertScreen(item2)
local state = ScreenList({}, action1)
state = ScreenList(state, action2)
expect(#state).to.equal(2)
expect(state[1].id).to.equal("foo")
expect(state[1].priority).to.equal(3)
expect(state[1].data).to.be.a("table")
end)
it("should remove screens", function()
local item = ScreenItem.new("foo", 1, {})
local action = InsertScreen(item)
local state = ScreenList({}, action)
local action2 = RemoveScreen(item)
state = ScreenList(state, action2)
expect(#state).to.equal(0)
end)
end)
end
@@ -0,0 +1,48 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local Immutable = require(Modules.Common.Immutable)
local FetchUserThumbnail = require(Modules.Shell.Actions.FetchUserThumbnail)
local SetUserThumbnail = require(Modules.Shell.Actions.SetUserThumbnail)
local ResetUserThumbnails = require(Modules.Shell.Actions.ResetUserThumbnails)
return function(state, action)
state = state or {}
if action.type == FetchUserThumbnail.name then
local rbxuid = action.rbxuid
local thumbnailType = action.thumbnailType
local thumbnailSize = action.thumbnailSize
local thumbnailId = table.concat{ rbxuid, thumbnailType.Name, thumbnailSize.Name }
local thumbnailData = state[thumbnailId] or {}
state = Immutable.Set(state, thumbnailId, Immutable.Set(thumbnailData, "isFetching", true))
elseif action.type == SetUserThumbnail.name then
local rbxuid = action.rbxuid
local thumbnailType = action.thumbnailType
local thumbnailSize = action.thumbnailSize
local thumbnailId = table.concat{ rbxuid, thumbnailType.Name, thumbnailSize.Name }
local thumbnailData = state[thumbnailId] or {}
--add fetchSuccess as fetchSuccess will indicate the last fetchSuccess or not (We can deduce it from imageUrl and lastUpdated, but it's more clear to have this in store)
if action.success and action.isFinal then --Only update image if fetch success and is final image
state = Immutable.Set(state, thumbnailId,
Immutable.JoinDictionaries(thumbnailData, {
fetchSuccess = true,
isFetching = false,
imageUrl = action.imageUrl,
lastUpdated = action.timestamp
})
)
else
state = Immutable.Set(state, thumbnailId,
Immutable.JoinDictionaries(thumbnailData, {
fetchSuccess = false,
isFetching = false,
--We need lastUpdated time
lastUpdated = action.timestamp
})
)
end
elseif action.type == ResetUserThumbnails.name then
state = {}
end
return state
end
@@ -0,0 +1,183 @@
return function()
local UserThumbnailsReducer = require(script.Parent.UserThumbnails)
local Actions = script.Parent.Parent.Actions
local FetchUserThumbnail = require(Actions.FetchUserThumbnail)
local SetUserThumbnail = require(Actions.SetUserThumbnail)
local ResetUserThumbnails = require(Actions.ResetUserThumbnails)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = UserThumbnailsReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action FetchUserThumbnail", function()
it("should set the user's thumbnail table based on rbxuid, thumbnailType and thumbnailSize, make the isFetching to be true", function()
local action = FetchUserThumbnail({ rbxuid = 12345, thumbnailType = Enum.ThumbnailType.AvatarThumbnail, thumbnailSize = Enum.ThumbnailSize.Size420x420 })
local state = UserThumbnailsReducer(nil, action)
local thumbnailId = table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name }
expect(state).to.be.a("table")
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(true)
end)
it("should concat the thumbnail tables", function()
local thumbnailIds = {}
local action = FetchUserThumbnail({ rbxuid = 12345, thumbnailType = Enum.ThumbnailType.AvatarThumbnail, thumbnailSize = Enum.ThumbnailSize.Size420x420 })
table.insert(thumbnailIds, table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name })
local state = UserThumbnailsReducer(nil, action)
action = FetchUserThumbnail({ rbxuid = 12345, thumbnailType = Enum.ThumbnailType.HeadShot, thumbnailSize = Enum.ThumbnailSize.Size180x180 })
table.insert(thumbnailIds, table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name })
state = UserThumbnailsReducer(state, action)
action = FetchUserThumbnail({ rbxuid = 12345, thumbnailType = Enum.ThumbnailType.AvatarThumbnail, thumbnailSize = Enum.ThumbnailSize.Size180x180 })
table.insert(thumbnailIds, table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name })
state = UserThumbnailsReducer(state, action)
action = FetchUserThumbnail({ rbxuid = 54321, thumbnailType = Enum.ThumbnailType.AvatarThumbnail, thumbnailSize = Enum.ThumbnailSize.Size180x180 })
table.insert(thumbnailIds, table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name })
state = UserThumbnailsReducer(state, action)
expect(state).to.be.a("table")
for _, thumbnailId in ipairs(thumbnailIds) do
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(true)
end
end)
end)
describe("Action SetUserThumbnail", function()
it("should set the user's thumbnail table based on rbxuid, fetchSuccess, lastUpdated, thumbnailTypeand thumbnailSize, make the isFetching to be false and set thumbnail assets if fetch success and is final image",
function()
local action = SetUserThumbnail(
{
rbxuid = 12345,
thumbnailType = Enum.ThumbnailType.HeadShot,
thumbnailSize = Enum.ThumbnailSize.Size180x180,
success = true,
isFinal = true,
imageUrl = "x",
timestamp = tick()
})
local thumbnailId = table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name }
local state = UserThumbnailsReducer(nil, action)
expect(state).to.be.a("table")
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(false)
expect(state[thumbnailId].fetchSuccess).to.equal(true)
expect(state[thumbnailId].imageUrl).to.equal("x")
expect(state[thumbnailId].lastUpdated).to.be.a("number")
end)
it("should set the user's thumbnail table based on rbxuid, fetchSuccess, lastUpdated, thumbnailType and thumbnailSize, make the isFetching to be false w/o set thumbnail assets if fetch failed or isn't final image",
function()
local action = SetUserThumbnail(
{
rbxuid = 12345,
thumbnailType = Enum.ThumbnailType.HeadShot,
thumbnailSize = Enum.ThumbnailSize.Size180x180,
success = true,
isFinal = false,
imageUrl = "y",
timestamp = tick()
})
local thumbnailId = table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name }
local state = UserThumbnailsReducer(nil, action)
expect(state).to.be.a("table")
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(false)
expect(state[thumbnailId].fetchSuccess).to.equal(false)
expect(state[thumbnailId].imageUrl).never.to.be.ok()
expect(state[thumbnailId].lastUpdated).to.be.a("number")
action = SetUserThumbnail(
{
rbxuid = 12345,
thumbnailType = Enum.ThumbnailType.HeadShot,
thumbnailSize = Enum.ThumbnailSize.Size180x180,
success = true,
isFinal = true,
imageUrl = "x",
timestamp = tick()
})
thumbnailId = table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name }
state = UserThumbnailsReducer(state, action)
expect(state).to.be.a("table")
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(false)
expect(state[thumbnailId].fetchSuccess).to.equal(true)
expect(state[thumbnailId].imageUrl).to.equal("x")
expect(state[thumbnailId].lastUpdated).to.be.a("number")
action = SetUserThumbnail(
{
rbxuid = 12345,
thumbnailType = Enum.ThumbnailType.HeadShot,
thumbnailSize = Enum.ThumbnailSize.Size180x180,
success = false,
timestamp = tick()
})
thumbnailId = table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name }
state = UserThumbnailsReducer(state, action)
expect(state).to.be.a("table")
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(false)
expect(state[thumbnailId].fetchSuccess).to.equal(false)
expect(state[thumbnailId].imageUrl).to.equal("x")
expect(state[thumbnailId].lastUpdated).to.be.a("number")
action = SetUserThumbnail(
{
rbxuid = 12345,
thumbnailType = Enum.ThumbnailType.HeadShot,
thumbnailSize = Enum.ThumbnailSize.Size180x180,
success = true,
isFinal = false,
imageUrl = "y",
timestamp = tick()
})
thumbnailId = table.concat{ action.rbxuid, action.thumbnailType.Name, action.thumbnailSize.Name }
state = UserThumbnailsReducer(state, action)
expect(state).to.be.a("table")
expect(state[thumbnailId]).to.be.a("table")
expect(state[thumbnailId].isFetching).to.equal(false)
expect(state[thumbnailId].fetchSuccess).to.equal(false)
expect(state[thumbnailId].imageUrl).to.equal("x")
expect(state[thumbnailId].lastUpdated).to.be.a("number")
end)
end)
describe("Action ResetUserThumbnails", function()
it("should reset the state to initial state after reset", function()
local action = FetchUserThumbnail({ rbxuid = 12345, thumbnailType = Enum.ThumbnailType.HeadShot, thumbnailSize = Enum.ThumbnailSize.Size180x180 })
local state = UserThumbnailsReducer(nil, action)
action = ResetUserThumbnails()
state = UserThumbnailsReducer(state, action)
expect(state).to.be.a("table")
expect(next(state)).never.to.be.ok()
action = SetUserThumbnail(
{
rbxuid = 12345,
thumbnailType = Enum.ThumbnailType.HeadShot,
thumbnailSize = Enum.ThumbnailSize.Size180x180,
success = true,
isFinal = true,
imageUrl = "x",
timestamp = tick()
})
state = UserThumbnailsReducer(nil, action)
action = ResetUserThumbnails()
state = UserThumbnailsReducer(state, action)
expect(state).to.be.a("table")
expect(next(state)).never.to.be.ok()
end)
end)
end
@@ -0,0 +1,15 @@
local Modules = game:GetService("CoreGui").RobloxGui.Modules
local SetXboxUser = require(Modules.Shell.Actions.SetXboxUser)
return function(state, action)
state = state or {}
if action.type == SetXboxUser.name then
return {
gamertag = action.gamertag,
xuid = action.xuid
}
end
return state
end
@@ -0,0 +1,38 @@
return function()
local XboxUserReducer = require(script.Parent.XboxUser)
local Actions = script.Parent.Parent.Actions
local SetXboxUser = require(Actions.SetXboxUser)
describe("initial state", function()
it("should return an initial table when passed nil", function()
local state = XboxUserReducer(nil, {})
expect(state).to.be.a("table")
end)
end)
describe("Action SetXboxUser", function()
it("should set the gamertag and xuid values in the store", function()
local action = SetXboxUser({gamertag = "TestGamerTag", xuid = 12345})
local state = XboxUserReducer(state, action)
expect(state).to.be.a("table")
expect(state.gamertag).to.be.a("string")
expect(state.gamertag).to.equal("TestGamerTag")
expect(state.xuid).to.be.a("number")
expect(state.xuid).to.equal(12345)
end)
it("should clear the gamertag and xuid values to nil when passed an empty SetXboxUser action", function()
local action = SetXboxUser({gamertag = "TestGamerTag", xuid = 12345})
local state = XboxUserReducer(state, action)
action = SetXboxUser({})
local state = XboxUserReducer(state, action)
expect(state).to.be.a("table")
expect(state.gamertag).to.equal(nil)
expect(state.xuid).to.equal(nil)
end)
end)
end