Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .darklua.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"process": [
"rules": [
{
"rule": "convert_require",
"current": {
Expand All @@ -14,6 +14,16 @@
"indexing_style": "wait_for_child"
}
},
{
"rule": "inject_global_value",
"identifier": "DEV",
"value": true
},
{
"rule": "inject_global_value",
"identifier": "__DEV__",
"value": true
},
"compute_expression",
"remove_unused_if_branch",
"remove_unused_while",
Expand Down
4 changes: 2 additions & 2 deletions foreman.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
rojo = { github = "rojo-rbx/rojo", version = "=7.4.4"}
selene = { github = "Kampfkarren/selene", version = "=0.27.1"}
stylua = { github = "JohnnyMorganz/StyLua", version = "=0.20.0"}
darklua = { github = "seaofvoices/darklua", version = "=0.13.1" }
luau-lsp = { github = "JohnnyMorganz/luau-lsp", version = "=1.32.3"}
darklua = { github = "seaofvoices/darklua", version = "=0.14.0" }
luau-lsp = { github = "JohnnyMorganz/luau-lsp", version = "=1.35.0"}
run-in-roblox = { github = "rojo-rbx/run-in-roblox", version = "=0.3.0" }
3 changes: 3 additions & 0 deletions jest.config.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
return {
testMatch = { '**/*.test' },
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
"lint:selene": "selene packages",
"format": "stylua .",
"style-check": "stylua . --check",
"test:roblox": "sh ./scripts/roblox-test.sh",
"verify-pack": "yarn workspaces foreach -A --no-private pack --dry-run",
"clean": "rm -rf node_modules"
},
"devDependencies": {
"@jsdotlua/jest": "^3.6.1-rc.2",
"@jsdotlua/jest-globals": "^3.6.1-rc.2",
"npmluau": "^0.1.1"
},
"packageManager": "yarn@4.0.2"
Expand Down
1 change: 1 addition & 0 deletions packages/react-lua-hooks/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "@seaofvoices/react-lua-hooks",
"description": "A collection of React hook for Luau",
"version": "0.1.0",
"repository": {
"type": "git",
Expand Down
1 change: 1 addition & 0 deletions packages/react-lua-use-constant/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "@seaofvoices/react-lua-use-constant",
"description": "A React hook to create a value once. Prefer using this hook from @seaofvoices/react-lua-hooks",
"version": "1.0.0",
"repository": {
"type": "git",
Expand Down
36 changes: 36 additions & 0 deletions packages/react-render-hook/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/.github/
/.vscode/
/scripts/
/docs/

/roblox
/build

.gitattributes
CHANGELOG.md

.yarn

.darklua*
.luau-analyze.json
.luaurc
foreman.toml
selene.toml
selene_definitions.yml
stylua.toml
.styluaignore

/globalTypes.d.lua
**/sourcemap.json
*.project.json

**/__tests__
**/*.test.lua
**/jest.config.lua

**/*.rbxl
**/*.rbxlx
**/*.rbxl.lock
**/*.rbxlx.lock
**/*.rbxm
**/*.rbxmx
5 changes: 5 additions & 0 deletions packages/react-render-hook/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## 0.1.0

* Initial version
76 changes: 76 additions & 0 deletions packages/react-render-hook/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<div align="center">

[![checks](https://github.com/seaofvoices/react-lua-hooks/actions/workflows/test.yml/badge.svg)](https://github.com/seaofvoices/react-lua-hooks/actions/workflows/test.yml)
![version](https://img.shields.io/npm/v/@seaofvoices/react-render-hook?label=version)
[![GitHub top language](https://img.shields.io/github/languages/top/seaofvoices/react-lua-hooks)](https://github.com/luau-lang/luau)
![license](https://img.shields.io/npm/l/@seaofvoices/react-render-hook)
![npm](https://img.shields.io/npm/dt/@seaofvoices/react-render-hook)

[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/seaofvoices)

</div>

# react-render-hook

A small utility function to quickly test React hooks.

## Installation

Add `react-render-hook` in your dependencies:

```bash
yarn add @seaofvoices/react-render-hook
```

Or if you are using `npm`:

```bash
npm install @seaofvoices/react-render-hook
```

## Content

- [renderHook](#renderhook)
- [createRenderHook](#createrenderhook)

## renderHook

```lua
function renderHook(hook, ...): {
result: Ref,
rerender: (...) -> (),
unmount: () -> ()
}
```

A function that takes a hook and its initial arguments and returns a `result` ref, a function to re-render and a function to unmount.

In a [jest](https://github.com/jsdotlua/jest-lua) test, it looks like this:

```lua
local function useCustomHook(input: string): string
return input .. " " .. input
end

it('returns the initial value after the first re-render', function()
local renderResult = renderHook(useCustomHook, 'text')

expect(renderResult.result.current).toBe("text text")

renderResult.rerender('bye')

expect(renderResult.result.current).toBe('bye bye')
end)
```

**Note about multiple returned values:** if the hook being rendered returns more than one value, those will be packed with `table.pack`. This means that the `renderResult.result.current` will contain an array.

### createRenderHook

If needed, you can pass custom [`renderOptions`](https://testing-library.com/docs/react-testing-library/api#render-options) to the `createRenderHook`.

Returns a new `renderHook` function.

## License

This project is available under the MIT license. See [LICENSE.txt](LICENSE.txt) for details.
26 changes: 26 additions & 0 deletions packages/react-render-hook/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "@seaofvoices/react-render-hook",
"description": "A test helper to render React hooks using react-testing-library",
"version": "0.1.0",
"repository": {
"type": "git",
"url": "https://github.com/seaofvoices/react-lua-hooks.git",
"directory": "packages/react-render-hook"
},
"keywords": [
"lua",
"luau",
"react",
"roblox",
"hook"
],
"license": "MIT",
"main": "./src/init.lua",
"dependencies": {
"@jsdotlua/react": "^17.1.0",
"@jsdotlua/react-testing-library": "^12.2.1-rc.1"
},
"devDependencies": {
"npmluau": "^0.1.1"
}
}
43 changes: 43 additions & 0 deletions packages/react-render-hook/src/createRenderHook.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
local React = require('@pkg/@jsdotlua/react')
local ReactTesting = require('@pkg/@jsdotlua/react-testing-library')

local function createRenderHook(renderOptions: { [string]: any }?)
local function renderHook(renderCallback, ...)
local args = table.pack(...)

local result = React.createRef()

local function TestComponent(props: { renderCallbackProps: { [number]: any, n: number } })
local renderCallbackProps = props.renderCallbackProps
local pendingResult = table.pack(
renderCallback(table.unpack(renderCallbackProps, 1, renderCallbackProps.n))
)

React.useEffect(function()
result.current = if pendingResult.n > 1
then pendingResult
else table.unpack(pendingResult, 1, 1)
end)

return nil
end

local renderResult = ReactTesting.render(
React.createElement(TestComponent, { renderCallbackProps = args }),
renderOptions or {}
)
local baseRerender = renderResult.rerender
local unmount = renderResult.unmount

local function rerender(...)
local args = table.pack(...)
return baseRerender(React.createElement(TestComponent, { renderCallbackProps = args }))
end

return { result = result, rerender = rerender, unmount = unmount }
end

return renderHook
end

return createRenderHook
6 changes: 6 additions & 0 deletions packages/react-render-hook/src/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
local createRenderHook = require('./createRenderHook')

return {
renderHook = createRenderHook(),
createRenderHook = createRenderHook,
}
1 change: 1 addition & 0 deletions packages/react-roblox-hooks/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "@seaofvoices/react-roblox-hooks",
"description": "A collection of React hooks specific to the Roblox environment",
"version": "0.1.0",
"repository": {
"type": "git",
Expand Down
3 changes: 3 additions & 0 deletions packages/react-roblox-use-service/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "@seaofvoices/react-roblox-use-service",
"description": "A React hook to easily obtain and mock Roblox services",
"version": "1.0.0",
"repository": {
"type": "git",
Expand All @@ -19,6 +20,8 @@
"@jsdotlua/react": "^17.1.0"
},
"devDependencies": {
"@jsdotlua/jest-globals": "^3.6.1-rc.2",
"@seaofvoices/react-render-hook": "workspace:^",
"npmluau": "^0.1.1"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
local React = require('@pkg/@jsdotlua/react')
local jestGlobals = require('@pkg/@jsdotlua/jest-globals')
local renderHook = require('@pkg/@seaofvoices/react-render-hook')

local ServiceProviderContext = require('../ServiceProviderContext')
local useService = require('../useService')

local expect = jestGlobals.expect
local it = jestGlobals.it
local beforeEach = jestGlobals.beforeEach

local services
local renderWithServices

beforeEach(function()
services = {}
renderWithServices = renderHook.createRenderHook({
wrapper = function(props)
return React.createElement(ServiceProviderContext.Provider, {
value = function(name)
return services[name]
end,
}, props.children)
end,
})
end)

it('returns the RunService', function()
local runServiceMock = {}

services.RunService = runServiceMock
local renderResult = renderWithServices(useService :: any, 'RunService')

expect(renderResult.result.current).toBe(runServiceMock)
end)

it('returns a different service after re-rendering', function()
local runServiceMock = {}
local workspaceMock = {}

services.RunService = runServiceMock
services.Workspace = workspaceMock
local renderResult = renderWithServices(useService :: any, 'RunService')

expect(renderResult.result.current).toBe(runServiceMock)

renderResult.rerender('Workspace')

expect(renderResult.result.current).toBe(workspaceMock)
end)

return nil
14 changes: 14 additions & 0 deletions roblox-test.server.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
local ReplicatedStorage = game:GetService('ReplicatedStorage')

local jest = require('@pkg/@jsdotlua/jest')

local success, result = jest.runCLI(ReplicatedStorage, {
color = false,
colors = false,
}, { ReplicatedStorage:FindFirstChild('node_modules'):FindFirstChild('@seaofvoices') }):await()

if not success then
error(result)
end

task.wait(0.5)
24 changes: 24 additions & 0 deletions scripts/roblox-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/sh

set -e

if [ ! -d node_modules ]; then
rm -rf roblox
yarn install
fi

if [ -d "roblox" ]; then
ls -d roblox/* | grep -v node_modules | xargs rm -rf
fi

rojo sourcemap test-place.project.json -o sourcemap.json

darklua process jest.config.lua roblox/jest.config.lua
darklua process roblox-test.server.lua roblox/roblox-test.server.lua
darklua process node_modules roblox/node_modules

cp test-place.project.json roblox/

rojo build roblox/test-place.project.json -o place.rbxl

run-in-roblox --place place.rbxl --script roblox/roblox-test.server.lua
Loading