local e=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\106\101\115\116-\103\108\111\098\097\108\115")local k=e.expect local p=e.beforeEach local f=e.it local S=e.jest local A=e.describe local M local O,X,o local L,r,q,K,h,a local F=0 local J={userName="\068\097\110"}local I={myVariable=90210}p(function()S.resetModules()M=require("\064\112\107\103\047\064\106\115\100\111\116\108\117\097\047\114\101\097\099\116")O=require("\046\046\047\082\101\097\099\116\085\112\100\097\116\101\081\117\101\117\101\046\110\101\119\046\108\117\097\117")X=require("\046\046\047\082\101\097\099\116\070\105\098\101\114\046\110\101\119\046\108\117\097\117")o=require("\046\046\047\082\101\097\099\116\070\105\098\101\114\076\097\110\101")r=M.Component:extend("\102\117\110\100\097\109\101\110\116\097\108")L=X.createFiberFromFundamental(r)K=o.NoLane q=O.createUpdate(F,K)h=false q.payload=I q.callback=function()h=true end q.lane=K end)A("\110\101\119 \082\101\097\099\116\085\112\100\097\116\101\081\117\101\117\101",function()f("\100\111\101\115 \110\111\116 \104\097\118\101 \102\111\114\099\101 \117\112\100\097\116\101",function()(k(O.checkHasForceUpdateAfterProcessing())).toEqual(false)end)f("\101\110\113\117\101\117\101 \098\101\102\111\114\101 \105\110\105\116\105\097\108\105\122\101 \105\115 \097 \110\111-\111\112",function()a=X.createWorkInProgress(L,{})O.enqueueUpdate(a,q);(k(a.updateQueue)).toEqual(nil)end)end)A("\105\110\105\116\105\097\108\105\122\101\100 \082\101\097\099\116\085\112\100\097\116\101\081\117\101\117\101",function()p(function()O.initializeUpdateQueue(a)end)f("\105\110\105\116\105\097\108\105\122\101\115 \102\105\098\101\114",function()(k(a.updateQueue)).toBeDefined()end)f("\101\110\113\117\101\117\101\115 \102\105\114\115\116 \117\112\100\097\116\101",function()(k(q.tag)).toBe(0)O.enqueueUpdate(a,q);(k(q.next)).toBe(q);(k(a.updateQueue.shared.pending)).toBe(q)end)f("\101\110\113\117\101\117\101\115 \115\097\109\101 \117\112\100\097\116\101 \116\119\105\099\101",function()O.enqueueUpdate(a,q)O.enqueueUpdate(a,q);(k(q.next)).toBe(q);(k(q.next.next)).toBe(q);(k(a.updateQueue.shared.pending)).toBe(q)end)end)A("\112\114\111\099\101\115\115\085\112\100\097\116\101\081\117\101\117\101",function()p(function()O.initializeUpdateQueue(L)a=X.createWorkInProgress(L,J)end)f("\119\105\116\104 \101\109\112\116\121 \113\117\101\117\101",function()O.processUpdateQueue(a,J,r,o.NoLanes);(k(a.memoizedState)).toBe(nil)end)f("\119\105\116\104 \110\111\110-\101\109\112\116\121 \113\117\101\117\101",function()O.enqueueUpdate(a,q);(k(a.memoizedState)).toBe(nil)O.processUpdateQueue(a,J,r,o.NoLanes);(k(h)).toBe(false);(k(a.memoizedState)).toEqual(I)end)end)A("\099\111\109\109\105\116\085\112\100\097\116\101\081\117\101\117\101",function()p(function()K=o.SomeRetryLane q=O.createUpdate(F,K)h=false q.payload=I q.callback=function()h=true end q.lane=K O.initializeUpdateQueue(L)a=X.createWorkInProgress(L,J)end)f("\119\105\116\104 \110\111\110-\101\109\112\116\121 \113\117\101\117\101",function()O.enqueueUpdate(a,q);(k(a.memoizedState)).toBe(nil)O.processUpdateQueue(a,J,r,o.RetryLanes);(k(L.updateQueue.effects)).never.toBe(nil)O.commitUpdateQueue(a,L.updateQueue,r);(k(h)).toBe(true)end)end)A("\101\110\113\117\101\117\101\067\097\112\116\117\114\101\100\085\112\100\097\116\101",function()p(function()K=o.NoLane q=O.createUpdate(F,K)q.tag=O.CaptureUpdate q.lane=K O.initializeUpdateQueue(L)a=X.createWorkInProgress(L,J)local e=require("\046\046\047\082\101\097\099\116\070\105\098\101\114\070\108\097\103\115")a.flags=bit32.bor(0,e.ShouldCapture)end)f("\115\101\116\115 \108\097\115\116\066\097\115\101\085\112\100\097\116\101",function()O.enqueueCapturedUpdate(a,q);(k(a.updateQueue.lastBaseUpdate)).toEqual(q)end)end)
--[[*
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
]]

local JestGlobals = require("@pkg/@jsdotlua/jest-globals")
local jestExpect = JestGlobals.expect
local beforeEach = JestGlobals.beforeEach
local it = JestGlobals.it
local jest = JestGlobals.jest
local describe = JestGlobals.describe

local React

local ReactUpdateQueue, Fiber, FiberLane
local fundamentalFiber, component, update, lane, setStateCallbackWasCalled, workInProgress

local updateTime = 0
local nextProps = { userName = "Dan" }
local updatePayload = { myVariable = 90210 }

beforeEach(function()
	jest.resetModules()

	React = require("@pkg/@jsdotlua/react")
	ReactUpdateQueue = require("../ReactUpdateQueue.new.luau")
	Fiber = require("../ReactFiber.new.luau")
	FiberLane = require("../ReactFiberLane")

	component = React.Component:extend("fundamental")
	fundamentalFiber = Fiber.createFiberFromFundamental(component)

	lane = FiberLane.NoLane
	update = ReactUpdateQueue.createUpdate(updateTime, lane)
	setStateCallbackWasCalled = false
	update.payload = updatePayload
	update.callback = function()
		setStateCallbackWasCalled = true
	end
	update.lane = lane
end)

describe("new ReactUpdateQueue", function()
	it("does not have force update", function()
		jestExpect(ReactUpdateQueue.checkHasForceUpdateAfterProcessing()).toEqual(false)
	end)

	it("enqueue before initialize is a no-op", function()
		workInProgress = Fiber.createWorkInProgress(fundamentalFiber, {})
		ReactUpdateQueue.enqueueUpdate(workInProgress, update)
		jestExpect(workInProgress.updateQueue).toEqual(nil)
	end)
end)

describe("initialized ReactUpdateQueue", function()
	beforeEach(function()
		ReactUpdateQueue.initializeUpdateQueue(workInProgress)
	end)

	it("initializes fiber", function()
		jestExpect(workInProgress.updateQueue).toBeDefined()
	end)

	it("enqueues first update", function()
		jestExpect(update.tag).toBe(0)

		ReactUpdateQueue.enqueueUpdate(workInProgress, update)
		jestExpect(update.next).toBe(update)
		jestExpect(workInProgress.updateQueue.shared.pending).toBe(update)
	end)

	it("enqueues same update twice", function()
		ReactUpdateQueue.enqueueUpdate(workInProgress, update)
		ReactUpdateQueue.enqueueUpdate(workInProgress, update)

		jestExpect(update.next).toBe(update)
		jestExpect(update.next.next).toBe(update)
		jestExpect(workInProgress.updateQueue.shared.pending).toBe(update)
	end)
end)

describe("processUpdateQueue", function()
	beforeEach(function()
		ReactUpdateQueue.initializeUpdateQueue(fundamentalFiber)
		workInProgress = Fiber.createWorkInProgress(fundamentalFiber, nextProps)
	end)

	it("with empty queue", function()
		ReactUpdateQueue.processUpdateQueue(
			workInProgress,
			nextProps,
			component,
			FiberLane.NoLanes
		)

		jestExpect(workInProgress.memoizedState).toBe(nil)
	end)

	it("with non-empty queue", function()
		ReactUpdateQueue.enqueueUpdate(workInProgress, update)
		jestExpect(workInProgress.memoizedState).toBe(nil)

		ReactUpdateQueue.processUpdateQueue(
			workInProgress,
			nextProps,
			component,
			FiberLane.NoLanes
		)

		jestExpect(setStateCallbackWasCalled).toBe(false)
		jestExpect(workInProgress.memoizedState).toEqual(updatePayload)
	end)
end)

describe("commitUpdateQueue", function()
	beforeEach(function()
		lane = FiberLane.SomeRetryLane
		update = ReactUpdateQueue.createUpdate(updateTime, lane)
		setStateCallbackWasCalled = false
		update.payload = updatePayload
		update.callback = function()
			setStateCallbackWasCalled = true
		end
		update.lane = lane
		ReactUpdateQueue.initializeUpdateQueue(fundamentalFiber)
		workInProgress = Fiber.createWorkInProgress(fundamentalFiber, nextProps)
	end)

	it("with non-empty queue", function()
		-- our update is Retry, since NoLane means the callback was already committed
		ReactUpdateQueue.enqueueUpdate(workInProgress, update)
		jestExpect(workInProgress.memoizedState).toBe(nil)

		-- we use RetryLanes here because the update lane needs to be a subset of that
		ReactUpdateQueue.processUpdateQueue(
			workInProgress,
			nextProps,
			component,
			FiberLane.RetryLanes
		)
		jestExpect(fundamentalFiber.updateQueue.effects).never.toBe(nil)

		ReactUpdateQueue.commitUpdateQueue(
			workInProgress,
			fundamentalFiber.updateQueue,
			component
		)

		jestExpect(setStateCallbackWasCalled).toBe(true)
	end)
end)

describe("enqueueCapturedUpdate", function()
	beforeEach(function()
		lane = FiberLane.NoLane
		update = ReactUpdateQueue.createUpdate(updateTime, lane)
		update.tag = ReactUpdateQueue.CaptureUpdate
		update.lane = lane
		ReactUpdateQueue.initializeUpdateQueue(fundamentalFiber)
		workInProgress = Fiber.createWorkInProgress(fundamentalFiber, nextProps)
		local ReactFiberFlags = require("../ReactFiberFlags")
		workInProgress.flags = bit32.bor(0, ReactFiberFlags.ShouldCapture)
	end)

	it("sets lastBaseUpdate", function()
		ReactUpdateQueue.enqueueCapturedUpdate(workInProgress, update)

		jestExpect(workInProgress.updateQueue.lastBaseUpdate).toEqual(update)
	end)
end)
