Merge pull request 'Merge 'feature/test-tools' into 'main'' (#1) from feature/test-tools into main
Reviewed-on: StarVision/wordpress-react-boilerplate#1
This commit is contained in:
commit
0f78f2ca50
14
wp/src/wp-content/plugins/wp-react/.eslintrc.json
Normal file
14
wp/src/wp-content/plugins/wp-react/.eslintrc.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jest": true
|
||||
},
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
12
wp/src/wp-content/plugins/wp-react/.prettierrc.json
Normal file
12
wp/src/wp-content/plugins/wp-react/.prettierrc.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"plugins": ["@prettier/plugin-php"]
|
||||
}
|
10
wp/src/wp-content/plugins/wp-react/.stylelintrc.json
Normal file
10
wp/src/wp-content/plugins/wp-react/.stylelintrc.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"defaultSeverity": "warning",
|
||||
"plugins": ["stylelint-scss"],
|
||||
"extends": ["stylelint-config-standard", "stylelint-config-sass-guidelines"],
|
||||
"rules": {
|
||||
"scss/at-extend-no-missing-placeholder": true,
|
||||
"selector-class-pattern": null,
|
||||
"no-empty-source": null
|
||||
}
|
||||
}
|
|
@ -9,48 +9,48 @@ use WpReact\Http\Ajax\AjaxEntry;
|
|||
|
||||
final class Hook
|
||||
{
|
||||
public function init(): void
|
||||
{
|
||||
foreach (get_class_methods($this) as $method) {
|
||||
if ($method !== 'init') {
|
||||
$this->{$method}();
|
||||
}
|
||||
}
|
||||
public function init(): void
|
||||
{
|
||||
foreach (get_class_methods($this) as $method) {
|
||||
if ($method !== 'init') {
|
||||
$this->{$method}();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function registerBirdsShortcode(): void
|
||||
{
|
||||
add_shortcode('wpreact_birds', static function (): string {
|
||||
add_action('wp_enqueue_scripts', function () {
|
||||
$path = WPREACT_PATH . 'assets/birds.js';
|
||||
$url = WPREACT_URL . 'assets/birds.js';
|
||||
private function registerBirdsShortcode(): void
|
||||
{
|
||||
add_shortcode('wpreact_birds', static function (): string {
|
||||
add_action('wp_enqueue_scripts', function () {
|
||||
$path = WPREACT_PATH . 'assets/birds.js';
|
||||
$url = WPREACT_URL . 'assets/birds.js';
|
||||
|
||||
wp_register_script('wpreact-birds-js', $url, [], $path);
|
||||
wp_register_script('wpreact-birds-js', $url, [], $path);
|
||||
|
||||
wp_localize_script('wpreact-birds-js', 'wpReactBirdsGlobals', [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('wpreact-birds'),
|
||||
]);
|
||||
wp_localize_script('wpreact-birds-js', 'wpReactBirdsGlobals', [
|
||||
'ajaxUrl' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('wpreact-birds'),
|
||||
]);
|
||||
|
||||
wp_enqueue_script('wpreact-birds-js');
|
||||
wp_enqueue_script('wpreact-birds-js');
|
||||
|
||||
$path = WPREACT_PATH . 'assets/style.css';
|
||||
$url = WPREACT_URL . 'assets/style.css';
|
||||
$path = WPREACT_PATH . 'assets/style.css';
|
||||
$url = WPREACT_URL . 'assets/style.css';
|
||||
|
||||
wp_register_style('wpreact-birds-css', $url, [], $path);
|
||||
wp_enqueue_style('wpreact-birds-css');
|
||||
});
|
||||
wp_register_style('wpreact-birds-css', $url, [], $path);
|
||||
wp_enqueue_style('wpreact-birds-css');
|
||||
});
|
||||
|
||||
return '<div id="wpreact-birds"></div>';
|
||||
});
|
||||
}
|
||||
return '<div id="wpreact-birds"></div>';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function registerApi(): void
|
||||
{
|
||||
$ajax_entry = new AjaxEntry();
|
||||
$ajax_entry->openEntry();
|
||||
}
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function registerApi(): void
|
||||
{
|
||||
$ajax_entry = new AjaxEntry();
|
||||
$ajax_entry->openEntry();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,42 +12,42 @@ use WpReact\Http\Ajax\Requests\GetBirdsRequest;
|
|||
|
||||
final class AjaxEntry
|
||||
{
|
||||
/**
|
||||
* Determine what method need to call when AJAX request comes.
|
||||
* Each action name points to a handler, which will be executed
|
||||
* when the request will be received.
|
||||
*
|
||||
* @return array<string, callable(): Handler>
|
||||
*/
|
||||
public function mapActionsToHandlers(): array
|
||||
{
|
||||
return [
|
||||
'get_birds' => function (): Handler {
|
||||
return new GetBirdsHandler(new GetBirdsRequest());
|
||||
},
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Determine what method need to call when AJAX request comes.
|
||||
* Each action name points to a handler, which will be executed
|
||||
* when the request will be received.
|
||||
*
|
||||
* @return array<string, callable(): Handler>
|
||||
*/
|
||||
public function mapActionsToHandlers(): array
|
||||
{
|
||||
return [
|
||||
'get_birds' => function (): Handler {
|
||||
return new GetBirdsHandler(new GetBirdsRequest());
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function openEntry(): void
|
||||
{
|
||||
foreach ($this->mapActionsToHandlers() as $action_name => $callback) {
|
||||
$action = function () use ($callback): void {
|
||||
check_ajax_referer('wpreact-birds');
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function openEntry(): void
|
||||
{
|
||||
foreach ($this->mapActionsToHandlers() as $action_name => $callback) {
|
||||
$action = function () use ($callback): void {
|
||||
check_ajax_referer('wpreact-birds');
|
||||
|
||||
try {
|
||||
echo $callback()->handle();
|
||||
} catch (Throwable $e) {
|
||||
echo Response::jsonError($e->getMessage());
|
||||
}
|
||||
|
||||
wp_die();
|
||||
};
|
||||
|
||||
add_action("wp_ajax_$action_name", $action);
|
||||
add_action("wp_ajax_nopriv_$action_name", $action);
|
||||
try {
|
||||
echo $callback()->handle();
|
||||
} catch (Throwable $e) {
|
||||
echo Response::jsonError($e->getMessage());
|
||||
}
|
||||
|
||||
wp_die();
|
||||
};
|
||||
|
||||
add_action("wp_ajax_$action_name", $action);
|
||||
add_action("wp_ajax_nopriv_$action_name", $action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,25 +9,25 @@ use WpReact\Http\Ajax\Response;
|
|||
|
||||
class GetBirdsHandler implements Handler
|
||||
{
|
||||
public function __construct(private GetBirdsRequest $request)
|
||||
{
|
||||
}
|
||||
public function __construct(private GetBirdsRequest $request)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(): string
|
||||
{
|
||||
$birds = [
|
||||
[
|
||||
'url' => 'https://i.imgur.com/GJKdVfL.jpeg',
|
||||
'title' => 'Bird looking right',
|
||||
],
|
||||
[
|
||||
'url' => 'https://i.imgur.com/1lC07Hh.jpeg',
|
||||
'title' => 'Cute sparrow bird',
|
||||
],
|
||||
];
|
||||
public function handle(): string
|
||||
{
|
||||
$birds = [
|
||||
[
|
||||
'url' => 'https://i.imgur.com/GJKdVfL.jpeg',
|
||||
'title' => 'Bird looking right',
|
||||
],
|
||||
[
|
||||
'url' => 'https://i.imgur.com/1lC07Hh.jpeg',
|
||||
'title' => 'Cute sparrow bird',
|
||||
],
|
||||
];
|
||||
|
||||
$birds = array_splice($birds, 0, $this->request->getBirdsLimit());
|
||||
$birds = array_splice($birds, 0, $this->request->getBirdsLimit());
|
||||
|
||||
return Response::json($birds);
|
||||
}
|
||||
return Response::json($birds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@ namespace WpReact\Http\Ajax\Handlers;
|
|||
|
||||
interface Handler
|
||||
{
|
||||
public function handle(): string;
|
||||
}
|
||||
public function handle(): string;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ namespace WpReact\Http\Ajax\Requests;
|
|||
|
||||
class GetBirdsRequest extends Request
|
||||
{
|
||||
private const DEFAULT_BIRDS_LIMIT = 2;
|
||||
private const DEFAULT_BIRDS_LIMIT = 2;
|
||||
|
||||
public function getBirdsLimit(): int
|
||||
{
|
||||
$limit = $this->data['birds_limit'] ?? self::DEFAULT_BIRDS_LIMIT;
|
||||
return (int) $limit;
|
||||
}
|
||||
}
|
||||
public function getBirdsLimit(): int
|
||||
{
|
||||
$limit = $this->data['birds_limit'] ?? self::DEFAULT_BIRDS_LIMIT;
|
||||
return (int) $limit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ namespace WpReact\Http\Ajax\Requests;
|
|||
|
||||
abstract class Request
|
||||
{
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $data;
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $data;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = $_POST;
|
||||
}
|
||||
public function __construct()
|
||||
{
|
||||
$this->data = $_POST;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,21 +8,21 @@ use JsonException;
|
|||
|
||||
class Response
|
||||
{
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public static function json(array|object $data): string
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public static function json(array|object $data): string
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
|
||||
return json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
return json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public static function jsonError(string $message): string
|
||||
{
|
||||
return self::json(['error' => WP_DEBUG ? $message : 'Server error']);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public static function jsonError(string $message): string
|
||||
{
|
||||
return self::json(['error' => WP_DEBUG ? $message : 'Server error']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
{
|
||||
"name": "serhiichornenkyi/wp-react",
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "^6.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WpReact\\": "app/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "SerhiiCho",
|
||||
"email": "serhiicho@protonmail.com"
|
||||
}
|
||||
],
|
||||
"require": {}
|
||||
"name": "serhiichornenkyi/wp-react",
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "^6.0",
|
||||
"phpunit/phpunit": "^11.0",
|
||||
"php-mock/php-mock": "^2.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"WpReact\\": "app/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "SerhiiCho",
|
||||
"email": "serhiicho@protonmail.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
1709
wp/src/wp-content/plugins/wp-react/composer.lock
generated
1709
wp/src/wp-content/plugins/wp-react/composer.lock
generated
File diff suppressed because it is too large
Load Diff
29
wp/src/wp-content/plugins/wp-react/jest.config.mjs
Normal file
29
wp/src/wp-content/plugins/wp-react/jest.config.mjs
Normal file
|
@ -0,0 +1,29 @@
|
|||
import preset from 'ts-jest/presets/index.js';
|
||||
|
||||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
export default {
|
||||
...preset.jsWithTsESM,
|
||||
testEnvironment: 'jsdom',
|
||||
setupFilesAfterEnv: ['<rootDir>/resources/ts/__tests__/config/importJestDOM.ts'],
|
||||
extensionsToTreatAsEsm: ['.ts'],
|
||||
transform: {
|
||||
'^.+\\.([tj]sx?)$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: 'tsconfig.json',
|
||||
useESM: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
testMatch: ['**/__tests__/!(config|mock)**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
|
||||
transformIgnorePatterns: ['<rootDir>/node_modules/(?!(@starconnect|nanoid)/)'],
|
||||
moduleNameMapper: {
|
||||
'\\.(css|less|scss|sass)$': '<rootDir>/resources/ts/__tests__/mock/styleMock.ts',
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
||||
'<rootDir>/resources/ts/__tests__/mock/fileMock.ts',
|
||||
'^test-utils$': '<rootDir>/resources/ts/utils/test-utils.tsx',
|
||||
'~/(.*)': '<rootDir>/resources/ts/$1',
|
||||
},
|
||||
// perf (you might try various options based on the available cores)
|
||||
maxWorkers: '8',
|
||||
};
|
|
@ -6,6 +6,8 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.23.9",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@prettier/plugin-php": "^0.22.2",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-image": "^3.0.3",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
|
@ -13,13 +15,34 @@
|
|||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@testing-library/jest-dom": "^6.4.2",
|
||||
"@testing-library/react": "^14.2.2",
|
||||
"@types/babel__core": "^7",
|
||||
"@types/crypto-js": "^4",
|
||||
"@types/eslint": "^8.56.5",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/moxios": "^0",
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@types/rollup-plugin-peer-deps-external": "^2",
|
||||
"@types/testing-library__react": "^10.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
||||
"@typescript-eslint/parser": "^7.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"moxios": "^0.4.0",
|
||||
"prettier": "^3.2.5",
|
||||
"rollup": "^4.12.0",
|
||||
"rollup-plugin-import-css": "^3.4.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-scss": "^4.0.0",
|
||||
"sass": "^1.72.0",
|
||||
"stylelint": "^16.2.1",
|
||||
"stylelint-config-sass-guidelines": "^11.1.0",
|
||||
"stylelint-config-standard": "^36.0.0",
|
||||
"ts-jest": "^29.1.2",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^4.8.2"
|
||||
},
|
||||
|
@ -30,7 +53,16 @@
|
|||
},
|
||||
"scripts": {
|
||||
"compose": "composer install",
|
||||
"build": "rollup --config"
|
||||
"build": "yarn lint && NODE_ENV=production rollup --config",
|
||||
"dev": "rollup --config --watch",
|
||||
"lint": "yarn lint.eslint && yarn lint.prettier && yarn lint.styles && yarn lint.types",
|
||||
"lint.eslint": "eslint . --ext ts",
|
||||
"lint.prettier": "prettier --ignore-path .gitignore --write \"**/*.{mjs,js,jsx,ts,tsx,json,php}\"",
|
||||
"lint.styles": "stylelint --ignore-path .gitignore \"**/*.{css,scss,sass}\" --fix",
|
||||
"lint.types": "tsc --noEmit",
|
||||
"test": "yarn test.react && yarn test.wordpress",
|
||||
"test.react": "jest",
|
||||
"test.wordpress": "./vendor/bin/phpunit tests"
|
||||
},
|
||||
"packageManager": "yarn@4.0.2"
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
import '@testing-library/jest-dom';
|
|
@ -0,0 +1,3 @@
|
|||
it('runs the first test', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
export default 'test-file-stub';
|
|
@ -0,0 +1 @@
|
|||
export default {};
|
|
@ -1,10 +1,8 @@
|
|||
import React from 'react'
|
||||
import Birds from './components/Birds/Birds'
|
||||
import React from 'react';
|
||||
import Birds from './components/Birds/Birds';
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<Birds />
|
||||
)
|
||||
}
|
||||
return <Birds />;
|
||||
};
|
||||
|
||||
export default App
|
||||
export default App;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
object-fit: cover;
|
||||
object-position: center;
|
||||
border-radius: 15px;
|
||||
box-shadow: 3px 3px 10px rgba(0, 0, 0, .1);
|
||||
box-shadow: 3px 3px 10px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
.Birds-item h2 {
|
||||
|
|
|
@ -1,43 +1,41 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import './Birds.css'
|
||||
import Request from '../../../modules/Request'
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import './Birds.css';
|
||||
import Request from '../../../modules/Request';
|
||||
|
||||
type Bird = {
|
||||
url: string
|
||||
title: string
|
||||
}
|
||||
url: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
const Birds: React.FC = () => {
|
||||
const [birds, setBirds] = useState<Bird[]>([])
|
||||
const [birds, setBirds] = useState<Bird[]>([]);
|
||||
|
||||
useEffect(() => fetchBirds(), [])
|
||||
useEffect(() => fetchBirds(), []);
|
||||
|
||||
function fetchBirds(): void {
|
||||
const params = {
|
||||
method: 'get_birds',
|
||||
params: [
|
||||
{ name: 'birds_limit', value: '2' },
|
||||
],
|
||||
}
|
||||
function fetchBirds(): void {
|
||||
const params = {
|
||||
method: 'get_birds',
|
||||
params: [{name: 'birds_limit', value: '2'}],
|
||||
};
|
||||
|
||||
new Request<Bird[]>(params)
|
||||
.send()
|
||||
.then(resp => setBirds(resp.data))
|
||||
.catch(err => console.error(err))
|
||||
}
|
||||
new Request<Bird[]>(params)
|
||||
.send()
|
||||
.then((resp) => setBirds(resp.data))
|
||||
.catch((err) => console.error(err));
|
||||
}
|
||||
|
||||
return (
|
||||
<ul className="Birds-list">
|
||||
{birds.map(bird => {
|
||||
return (
|
||||
<li key={bird.title} className="Birds-item">
|
||||
<img src={bird.url} alt={bird.title} />
|
||||
<h2>{bird.title}</h2>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ul className="Birds-list">
|
||||
{birds.map((bird) => {
|
||||
return (
|
||||
<li key={bird.title} className="Birds-item">
|
||||
<img src={bird.url} alt={bird.title} />
|
||||
<h2>{bird.title}</h2>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default Birds
|
||||
export default Birds;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import React from "react"
|
||||
import { render } from "react-dom"
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import App from './App'
|
||||
import React from 'react';
|
||||
import {render} from 'react-dom';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const target = document.getElementById('wpreact-birds')
|
||||
const target = document.getElementById('wpreact-birds');
|
||||
|
||||
if (!target) {
|
||||
throw new Error('Cannot find element #wpreact-birds')
|
||||
}
|
||||
if (!target) {
|
||||
throw new Error('Cannot find element #wpreact-birds');
|
||||
}
|
||||
|
||||
const root = createRoot(target)
|
||||
const root = createRoot(target);
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
)
|
||||
})
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
interface Window {
|
||||
wpReactBirdsGlobals: {
|
||||
ajaxUrl: string
|
||||
nonce: string
|
||||
}
|
||||
}
|
||||
wpReactBirdsGlobals: {
|
||||
ajaxUrl: string;
|
||||
nonce: string;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
import axios from 'axios'
|
||||
import axios from 'axios';
|
||||
|
||||
export type RequestData = {
|
||||
method: string
|
||||
params?: string | { name: string, value: string | Blob }[]
|
||||
}
|
||||
method: string;
|
||||
params?: string | {name: string; value: string | Blob}[];
|
||||
};
|
||||
|
||||
export type RequestInterface = {
|
||||
send: () => Promise<any>
|
||||
}
|
||||
send: () => Promise<any>;
|
||||
};
|
||||
|
||||
class Request<T> implements RequestInterface {
|
||||
private readonly data: RequestData
|
||||
private readonly data: RequestData;
|
||||
|
||||
public constructor(data: RequestData) {
|
||||
this.data = data
|
||||
public constructor(data: RequestData) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public send(): Promise<{data: T}> {
|
||||
return axios.post(window.wpReactBirdsGlobals.ajaxUrl, this.createParams());
|
||||
}
|
||||
|
||||
private createParams(): FormData {
|
||||
const params = new FormData();
|
||||
|
||||
params.append('action', this.data.method);
|
||||
params.append('_ajax_nonce', window.wpReactBirdsGlobals.nonce);
|
||||
|
||||
if (this.data.params) {
|
||||
if (typeof this.data.params === 'string') {
|
||||
params.append('data', this.data.params);
|
||||
} else {
|
||||
this.data.params.forEach((param) => {
|
||||
params.append(param.name, param.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public send(): Promise<{ data: T }> {
|
||||
return axios.post(window.wpReactBirdsGlobals.ajaxUrl, this.createParams())
|
||||
}
|
||||
|
||||
private createParams(): FormData {
|
||||
const params = new FormData()
|
||||
|
||||
params.append('action', this.data.method)
|
||||
params.append('_ajax_nonce', window.wpReactBirdsGlobals.nonce)
|
||||
|
||||
if (this.data.params) {
|
||||
if (typeof this.data.params === 'string') {
|
||||
params.append('data', this.data.params)
|
||||
} else {
|
||||
this.data.params.forEach(param => {
|
||||
params.append(param.name, param.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
return params;
|
||||
}
|
||||
}
|
||||
|
||||
export default Request
|
||||
export default Request;
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import React, {ReactElement} from 'react';
|
||||
import {render, RenderOptions} from '@testing-library/react';
|
||||
|
||||
const AllTheProviders = ({children}: {children: React.ReactNode}) => {
|
||||
return <React.Fragment>{children}</React.Fragment>;
|
||||
};
|
||||
|
||||
const customRender = (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>) =>
|
||||
render(ui, {wrapper: AllTheProviders, ...options});
|
||||
|
||||
const mockedMethods = ['log', 'warn', 'error'];
|
||||
export const {originalConsoleFuncs, consoleMessages} = mockedMethods.reduce(
|
||||
(acc: any, method: any) => {
|
||||
acc.originalConsoleFuncs[method] = console[method].bind(console);
|
||||
acc.consoleMessages[method] = [];
|
||||
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
consoleMessages: {},
|
||||
originalConsoleFuncs: {},
|
||||
}
|
||||
);
|
||||
|
||||
export const clearConsole = () =>
|
||||
mockedMethods.forEach((method) => {
|
||||
consoleMessages[method] = [];
|
||||
});
|
||||
|
||||
export const mockConsole = (callOriginals?: boolean) => {
|
||||
const createMockConsoleFunc = (method: any) => {
|
||||
console[method] = (...args: any[]) => {
|
||||
consoleMessages[method].push(args);
|
||||
if (callOriginals) return originalConsoleFuncs[method](...args);
|
||||
};
|
||||
};
|
||||
|
||||
const deleteMockConsoleFunc = (method: any) => {
|
||||
console[method] = originalConsoleFuncs[method];
|
||||
consoleMessages[method] = [];
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
mockedMethods.forEach((method: any) => {
|
||||
createMockConsoleFunc(method);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockedMethods.forEach((method: any) => {
|
||||
deleteMockConsoleFunc(method);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export * from '@testing-library/react';
|
||||
export {customRender as render};
|
|
@ -3,41 +3,53 @@ import resolve from '@rollup/plugin-node-resolve';
|
|||
import replace from '@rollup/plugin-replace';
|
||||
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import css from "rollup-plugin-import-css";
|
||||
import sass from 'sass';
|
||||
import scss from 'rollup-plugin-scss';
|
||||
import image from '@rollup/plugin-image';
|
||||
import json from '@rollup/plugin-json';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
|
||||
export default {
|
||||
input: 'resources/ts/birds/main.tsx',
|
||||
output: [
|
||||
{
|
||||
file: 'assets/birds.js',
|
||||
name: 'app',
|
||||
sourcemap: 'inline',
|
||||
format: 'es',
|
||||
inlineDynamicImports: true
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
peerDepsExternal(),
|
||||
resolve({
|
||||
browser: true,
|
||||
dedupe: ['react', 'react-dom'],
|
||||
}),
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
}),
|
||||
commonjs(),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.json',
|
||||
sourceMap: true,
|
||||
inlineSources: true,
|
||||
}),
|
||||
image(),
|
||||
css({ output: 'style.css', minify: true }),
|
||||
json(),
|
||||
terser()
|
||||
],
|
||||
};
|
||||
input: 'resources/ts/birds/main.tsx',
|
||||
output: [
|
||||
{
|
||||
file: 'assets/birds.js',
|
||||
name: 'app',
|
||||
sourcemap: 'inline',
|
||||
format: 'es',
|
||||
inlineDynamicImports: true,
|
||||
},
|
||||
],
|
||||
onwarn(warning, warn) {
|
||||
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
|
||||
return;
|
||||
}
|
||||
warn(warning);
|
||||
},
|
||||
plugins: [
|
||||
peerDepsExternal(),
|
||||
resolve({
|
||||
browser: true,
|
||||
dedupe: ['react', 'react-dom'],
|
||||
}),
|
||||
replace({
|
||||
preventAssignment: true,
|
||||
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
}),
|
||||
commonjs(),
|
||||
typescript({
|
||||
tsconfig: 'tsconfig.json',
|
||||
sourceMap: true,
|
||||
inlineSources: true,
|
||||
}),
|
||||
image(),
|
||||
scss({
|
||||
fileName: 'style.css',
|
||||
outputStyle: process.env.NODE_ENV === 'production' ? 'compressed' : 'expanded',
|
||||
runtime: sass,
|
||||
failOnError: true,
|
||||
}),
|
||||
json(),
|
||||
terser(),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WpReact\unit\Http\Ajax;
|
||||
|
||||
use phpmock\Mock;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class GetBirdsTest extends TestCase
|
||||
{
|
||||
public function test_handler(): void
|
||||
{
|
||||
$handle = new Mock(__NAMESPACE__, 'handle', function () {
|
||||
return 3;
|
||||
});
|
||||
|
||||
$handle->enable();
|
||||
$this->assertEquals(3, handle());
|
||||
}
|
||||
}
|
|
@ -1,11 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
|
@ -16,18 +12,17 @@
|
|||
"moduleResolution": "node",
|
||||
"noImplicitAny": false,
|
||||
"resolveJsonModule": true,
|
||||
"noEmitOnError": true,
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"react": [
|
||||
"./node_modules/@types/react"
|
||||
]
|
||||
}
|
||||
"react": ["./node_modules/@types/react"],
|
||||
"test-utils": ["./resources/ts/utils/test-utils"],
|
||||
"~/*": ["./resources/ts/*"]
|
||||
},
|
||||
"typeRoots": ["./node_modules/@types", "./node_modules/@testing-library"],
|
||||
"types": ["jest", "jest-dom"]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"include": [
|
||||
"resources/ts/**/*.ts",
|
||||
"resources/ts/**/*.tsx"
|
||||
],
|
||||
}
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["resources/ts/**/*.ts", "resources/ts/**/*.tsx"]
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ Text Domain: wpreact
|
|||
Tags: react, typescript, tutorial, test-plugin, psr12
|
||||
*/
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
defined('ABSPATH') || exit();
|
||||
define('WPREACT_PATH', plugin_dir_path(__FILE__));
|
||||
define('WPREACT_URL', plugin_dir_url(__FILE__));
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
try {
|
||||
(new WpReact\Hook())->init();
|
||||
(new WpReact\Hook())->init();
|
||||
} catch (Throwable $e) {
|
||||
error_log($e->getMessage());
|
||||
error_log($e->getMessage());
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user