/* eslint-disable @typescript-eslint/no-empty-function */
import { describe, expect, it, vi } from "vitest";
import { transform } from "../../../../test/helpers/babelTransform.js";
describe("className visitor - window dimensions (w-screen/h-screen)", () => {
it("should inject useWindowDimensions hook for w-screen in function component", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
const output = transform(input, undefined, true);
// Should import useWindowDimensions
expect(output).toContain("useWindowDimensions");
expect(output).toMatch(/import.*useWindowDimensions.*from ['"]react-native['"]/);
// Should inject hook call
expect(output).toContain("_twDimensions");
expect(output).toContain("useWindowDimensions()");
// Should generate inline style with width
expect(output).toMatch(/width:\s*_twDimensions\.width/);
// Should have StyleSheet for static styles
expect(output).toContain("_twStyles");
expect(output).toContain("backgroundColor:");
});
it("should inject useWindowDimensions hook for h-screen in function component", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
const output = transform(input, undefined, true);
// Should import useWindowDimensions
expect(output).toContain("useWindowDimensions");
// Should inject hook call
expect(output).toContain("_twDimensions");
expect(output).toContain("useWindowDimensions()");
// Should generate inline style with height
expect(output).toMatch(/height:\s*_twDimensions\.height/);
});
it("should handle both w-screen and h-screen together", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
function FullScreenView() {
return ;
}
`;
const output = transform(input, undefined, true);
// Should inject hook
expect(output).toContain("useWindowDimensions()");
// Should generate inline style with both dimensions
expect(output).toMatch(/width:\s*_twDimensions\.width/);
expect(output).toMatch(/height:\s*_twDimensions\.height/);
// Should have StyleSheet for static styles
expect(output).toContain("backgroundColor:");
});
it("should handle w-screen/h-screen with arrow function component", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
const MyComponent = () => {
return ;
};
`;
const output = transform(input, undefined, true);
// Should inject hook
expect(output).toContain("useWindowDimensions()");
expect(output).toMatch(/width:\s*_twDimensions\.width/);
});
it("should handle concise arrow function and inject hook", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
const MyComponent = () => ;
`;
const output = transform(input, undefined, true);
// Should convert concise arrow to block statement and inject hook
expect(output).toContain("useWindowDimensions()");
expect(output).toContain("return");
expect(output).toMatch(/width:\s*_twDimensions\.width/);
});
it("should merge useWindowDimensions with existing react-native import", () => {
const input = `
import React from 'react';
import { View, Text } from 'react-native';
function MyComponent() {
return ;
}
`;
const output = transform(input, undefined, true);
// Should merge useWindowDimensions into existing import (not create separate import)
// The key is that useWindowDimensions should be imported
expect(output).toContain("useWindowDimensions");
});
it("should warn when w-screen/h-screen used outside function component", () => {
const consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
const input = `
import React from 'react';
import { View } from 'react-native';
class MyComponent extends React.Component {
render() {
return ;
}
}
`;
transform(input, undefined, true);
// Should warn about usage in class component
expect(consoleWarnSpy).toHaveBeenCalledWith(
expect.stringContaining("w-screen/h-screen classes require a function component scope"),
);
consoleWarnSpy.mockRestore();
});
it("should combine w-screen with other static classes", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
function MyComponent() {
return ;
}
`;
const output = transform(input, undefined, true);
// Should have static styles in StyleSheet
expect(output).toContain("padding:");
expect(output).toContain("backgroundColor:");
expect(output).toContain("borderRadius:");
// Should have runtime dimension
expect(output).toMatch(/width:\s*_twDimensions\.width/);
// Should combine as array
expect(output).toContain("_twStyles");
expect(output).toContain("_twDimensions");
});
it("should inject hook only once even with multiple w-screen/h-screen uses", () => {
const input = `
import React from 'react';
import { View } from 'react-native';
function MyComponent() {
return (
<>
>
);
}
`;
const output = transform(input, undefined, true);
// Count occurrences of hook injection (should be exactly 1)
const hookMatches = output.match(/_twDimensions\s*=\s*useWindowDimensions\(\)/g) ?? [];
expect(hookMatches.length).toBe(1);
});
it("should handle aliased useWindowDimensions import", () => {
const input = `
import React from 'react';
import { View, useWindowDimensions as useDims } from 'react-native';
function MyComponent() {
const dims = useDims();
return ;
}
`;
const output = transform(input, undefined, true);
// Should use the aliased name
expect(output).toContain("useDims()");
// Should still generate _twDimensions variable for our use
expect(output).toContain("_twDimensions");
});
it("should error when w-screen is combined with dark: modifier", () => {
const input = `
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with color scheme modifiers/,
);
});
it("should error when h-screen is combined with light: modifier", () => {
const input = `
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with color scheme modifiers/,
);
});
it("should error when w-screen is combined with active: modifier", () => {
const input = `
import { Pressable } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with state modifiers/,
);
});
it("should error when h-screen is combined with hover: modifier", () => {
const input = `
import { Pressable } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with state modifiers/,
);
});
it("should error when w-screen is combined with ios: modifier", () => {
const input = `
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with.*platform modifiers/,
);
});
it("should error when h-screen is combined with android: modifier", () => {
const input = `
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with.*platform modifiers/,
);
});
it("should error when w-screen is used in tw`` call", () => {
const input = `
import { tw } from '@mgcrea/react-native-tailwind';
export function MyComponent() {
const styles = tw\`w-screen bg-white\`;
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen are not supported in tw.*or twStyle/,
);
});
it("should error when h-screen is used in twStyle() call", () => {
const input = `
import { twStyle } from '@mgcrea/react-native-tailwind';
export function MyComponent() {
const styles = twStyle('h-screen p-4');
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen are not supported in tw.*or twStyle/,
);
});
it("should properly merge w-screen with Pressable style function", () => {
const input = `
import { Pressable } from 'react-native';
export function MyComponent() {
return (
[pressed && { opacity: 0.5 }]}
/>
);
}
`;
const output = transform(input, undefined, true);
// Should inject useWindowDimensions hook
expect(output).toContain("useWindowDimensions");
expect(output).toContain("_twDimensions");
// Should wrap the style function properly
expect(output).toContain("_state");
// Should contain the runtime dimension access
expect(output).toContain("_twDimensions.width");
// Should call the existing function
expect(output).toContain("pressed");
});
it("should properly merge h-screen with arrow function style", () => {
const input = `
import { Pressable } from 'react-native';
export function MyComponent() {
return (
state.pressed ? { opacity: 0.8 } : null}
/>
);
}
`;
const output = transform(input, undefined, true);
// Should inject useWindowDimensions hook
expect(output).toContain("useWindowDimensions");
expect(output).toContain("_twDimensions");
// Should wrap the style function
expect(output).toContain("_state");
// Should contain the runtime dimension access
expect(output).toContain("_twDimensions.height");
// Should call the original function
expect(output).toContain("state.pressed");
});
it("should error when w-screen is in base classes with dark: modifier", () => {
const input = `
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with modifiers/,
);
});
it("should error when w-screen is in base classes with ios: modifier", () => {
const input = `
import { View } from 'react-native';
export function MyComponent() {
return ;
}
`;
expect(() => transform(input, undefined, true)).toThrow(
/w-screen and h-screen cannot be combined with modifiers/,
);
});
});