test: setup tailwindcss tests

This commit is contained in:
Mark Lawlor
2022-04-07 17:04:59 +10:00
parent e0bce17edc
commit 3fc8da7bfc
9 changed files with 127 additions and 25 deletions

View File

@@ -0,0 +1,68 @@
import { tailwindRunner, Case } from "./runner";
const cases: Array<Case> = [
[
"Layout - Container",
[
[
"container",
{
styles: {
container: { width: "100%" },
container1: { maxWidth: 640 },
container2: { maxWidth: 768 },
container3: { maxWidth: 1024 },
container4: { maxWidth: 1280 },
container5: { maxWidth: 1536 },
},
media: {
container: [
{ media: ["(min-width: 640px)"], suffix: 1 },
{ media: ["(min-width: 768px)"], suffix: 2 },
{ media: ["(min-width: 1024px)"], suffix: 3 },
{ media: ["(min-width: 1280px)"], suffix: 4 },
{ media: ["(min-width: 1536px)"], suffix: 5 },
],
},
},
],
[
"sm:container",
{
styles: {
"sm\\:container0": { width: "100%" },
"sm\\:container1": { maxWidth: 640 },
"sm\\:container2": { maxWidth: 768 },
"sm\\:container3": { maxWidth: 1024 },
"sm\\:container4": { maxWidth: 1280 },
"sm\\:container5": { maxWidth: 1536 },
},
media: {
"sm\\:container": [
{ media: ["(min-width: 640px)"], suffix: 0 },
{ media: ["(min-width: 640px)"], suffix: 1 },
{
media: ["(min-width: 640px)", "(min-width: 768px)"],
suffix: 2,
},
{
media: ["(min-width: 640px)", "(min-width: 1024px)"],
suffix: 3,
},
{
media: ["(min-width: 640px)", "(min-width: 1280px)"],
suffix: 4,
},
{
media: ["(min-width: 640px)", "(min-width: 1536px)"],
suffix: 5,
},
],
},
},
],
],
],
];
tailwindRunner(cases);

View File

@@ -0,0 +1,30 @@
import { MediaRecord, StyleRecord } from "../../src/babel/types";
import { processStyles } from "../../src/babel/utils/process-styles";
export type Case = [string, Array<Test>];
export type Test = [string, Expected];
export interface Expected {
styles: StyleRecord;
media?: MediaRecord;
}
export function tailwindRunner(cases: Case[]) {
describe.each(cases)("%s", (_, testCases) => {
test.each(testCases)(
"%s",
(css, { styles: expectedStyles, media: expectedMedia }) => {
const { styles, media } = processStyles({
theme: {},
content: [{ raw: `<div class="${css}">`, extension: "html" } as any],
});
expect(styles).toEqual(expectedStyles);
if (expectedMedia) {
expect(media).toEqual(expectedMedia);
}
}
);
});
}

View File

@@ -7,5 +7,6 @@ module.exports = {
"/__tests__/native-context-fixtures/",
"/__tests__/native-inline-fixtures/",
"/__tests__/web-fixtures/",
"/__tests__/tailwindcss/runner.ts",
],
};

View File

@@ -15,7 +15,7 @@ export default function (
cwd: string
) {
const tailwindConfig = getTailwindConfig(cwd, options);
const { styles, media } = processStyles(babel, tailwindConfig);
const { styles, media } = processStyles(tailwindConfig);
return {
visitor: {

View File

@@ -71,7 +71,7 @@ export default function (
/**
* Override tailwind to only process the classnames in this file
*/
const { styles, media } = processStyles(babel, {
const { styles, media } = processStyles({
...tailwindConfig,
// Make sure its relative to the tailwind.config.js
content: [relative(rootDir, filename)],

View File

@@ -1,9 +1,15 @@
import { ViewStyle, TextStyle, ImageStyle } from "react-native";
import * as BabelCore from "@babel/core";
export type Style = ViewStyle | TextStyle | ImageStyle;
export type Babel = typeof BabelCore;
export type Style = ViewStyle | TextStyle | ImageStyle;
export type StyleRecord = Record<string, ViewStyle | TextStyle | ImageStyle>;
export type MediaRecord = Record<
string,
Array<{ media: string[]; suffix: number }>
>;
export interface TailwindReactNativeOptions {
tailwindConfigPath?: string;
platform?: "web" | "native" | "native-context" | "native-inline";

View File

@@ -3,7 +3,7 @@ import { TailwindConfig } from "tailwindcss/tailwind-config";
import { AtRule, Comment, Media, Rule, StyleRules } from "css";
import { normaliseSelector } from "../../shared/selector";
import { Babel, Style } from "../types";
import { Style } from "../types";
import { isValidStyle } from "./is-valid-style";
interface CssRule {
@@ -19,14 +19,13 @@ interface CssRule {
* - flattens styles to be react-native style objects
*/
export function flattenRules(
babel: Babel,
cssRules: StyleRules["rules"],
tailwindConfig: TailwindConfig,
media: string[] = []
): CssRule[] {
return cssRules.flatMap((cssRule) => {
if (isMedia(cssRule)) {
return flattenRules(babel, cssRule.rules ?? [], tailwindConfig, [
return flattenRules(cssRule.rules ?? [], tailwindConfig, [
...new Set(cssRule.media ? [...media, cssRule.media] : media),
]);
} else if (isRule(cssRule)) {

View File

@@ -1,11 +1,12 @@
import { Expression, Statement } from "@babel/types";
import { Babel } from "../types";
import { Statement } from "@babel/types";
import serialize from "babel-literal-to-ast";
import { Babel, MediaRecord, StyleRecord } from "../types";
export function appendVariables(
babel: Babel,
body: Statement[],
styles: Expression,
media: Expression
styles: StyleRecord,
media: MediaRecord
) {
const { types: t } = babel;
@@ -18,7 +19,7 @@ export function appendVariables(
t.identifier("StyleSheet"),
t.identifier("create")
),
[styles]
[serialize(styles)]
)
),
])
@@ -26,7 +27,7 @@ export function appendVariables(
body.push(
t.variableDeclaration("const", [
t.variableDeclarator(t.identifier("__tailwindMedia"), media),
t.variableDeclarator(t.identifier("__tailwindMedia"), serialize(media)),
])
);
}

View File

@@ -1,4 +1,4 @@
import { Babel, Style } from "../types";
import { MediaRecord, Style, StyleRecord } from "../types";
import css from "css";
import postcss from "postcss";
@@ -6,15 +6,15 @@ import tailwind from "tailwindcss";
import postcssCssvariables from "postcss-css-variables";
import postcssColorRBG from "postcss-color-rgb";
import postcssRemToPixel from "postcss-rem-to-pixel";
import serialize from "babel-literal-to-ast";
import { flattenRules } from "./flatten-rules";
import { normaliseSelector } from "../../shared/selector";
import { TailwindConfig } from "tailwindcss/tailwind-config";
export function processStyles(babel: Babel, tailwindConfig: TailwindConfig) {
const cssInput = "@tailwind utilities";
export function processStyles(
tailwindConfig: TailwindConfig,
cssInput: string = "@tailwind components;@tailwind utilities;"
) {
const processedCss = postcss([
tailwind(tailwindConfig),
postcssCssvariables(),
@@ -36,13 +36,10 @@ export function processStyles(babel: Babel, tailwindConfig: TailwindConfig) {
const cssRules = css.parse(processedCss).stylesheet?.rules ?? [];
const parsedRules = flattenRules(babel, cssRules, tailwindConfig);
const parsedRules = flattenRules(cssRules, tailwindConfig);
const styles: Record<string, Style> = {};
const mediaRules: Record<
string,
Array<{ media: string[]; suffix: number }>
> = {};
const styles: StyleRecord = {};
const mediaRules: MediaRecord = {};
for (const [suffix, parsedRule] of parsedRules.entries()) {
const { selector, media, rules } = parsedRule;
@@ -66,7 +63,7 @@ export function processStyles(babel: Babel, tailwindConfig: TailwindConfig) {
}
return {
styles: serialize(styles),
media: serialize(mediaRules),
styles,
media: mediaRules,
};
}