Skip to content
Open
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
47 changes: 47 additions & 0 deletions test/blackbox-tests/data-attributes.t/run.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
DOM JSX currently rejects arbitrary data attributes. These expected failures
document the limitation before adding support for them.

$ cat > dune-project <<EOF
> (lang dune 3.8)
> (using melange 0.1)
> EOF

$ cat > dune <<EOF
> (melange.emit
> (target output)
> (alias mel)
> (emit_stdlib false)
> (libraries reason-react)
> (preprocess (pps melange.ppx reason-react-ppx)))
> EOF

Check the failure status before showing the final diagnostic, since the full
list of accepted DOM props is long.

$ cat > input.re <<EOF
> let element = <div dataFoo="value" />;
> EOF
$ dune build @mel > error.log 2>&1
[1]
$ tail -n 1 error.log
This argument cannot be applied with label ~dataFoo

Optional data attributes are also rejected.

$ cat > input.re <<EOF
> let element = (~dataFoo=?, ()) => <div ?dataFoo />;
> EOF
$ dune build @mel > error.log 2>&1
[1]
$ tail -n 1 error.log
This argument cannot be applied with label ?dataFoo

SVG elements have the same limitation.

$ cat > input.re <<EOF
> let element = <svg dataFoo="value" />;
> EOF
$ dune build @mel > error.log 2>&1
[1]
$ tail -n 1 error.log
This argument cannot be applied with label ~dataFoo
45 changes: 45 additions & 0 deletions test/blackbox-tests/dom-props.t/input.re.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
let first = <div className="first" />;
let second = <div id="second" />;
let ordinaryData = <object data="file" datatype="text" />;

let optional = (~className=?, ()) => <div ?className />;

let renamed =
<div
ariaLabel="label"
ariaActivedescendant="descendant"
as_="button"
begin_="0"
end_="1"
in_="source"
open_=true
to_="target"
type_="button"
/>;

let withChildren = <div key="parent"> <span /> <span /> </div>;

let withRefAndEvent = (elementRef, handleClick) =>
<button ref=elementRef onClick=handleClick />;

let optionalKey = (~key=?, ()) => <div ?key />;

module Component = {
[@react.component]
let make = (~dataFoo) => <div> dataFoo->React.string </div>;
};

let component = <Component dataFoo="component" />;

module IntegerComponent = {
[@react.component]
let make = (~dataFoo: int) => <div> dataFoo->React.int </div>;
};

let integerComponent = <IntegerComponent dataFoo=42 />;

external next: string => string = "next";
let effects = <div className={next("class")} id={next("id")} />;

external nextUnit: unit => unit = "nextUnit";
let effectfulUnit = [@JSX] div(~className="unit", nextUnit());
227 changes: 227 additions & 0 deletions test/blackbox-tests/dom-props.t/run.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
DOM props retain their types and JavaScript names. Component props named
dataFoo are ordinary component props, including when their type is int.

$ cat > dune-project <<EOF
> (lang dune 3.8)
> (using melange 0.1)
> EOF

$ cat > dune <<EOF
> (melange.emit
> (target output)
> (alias mel)
> (emit_stdlib false)
> (libraries reason-react)
> (preprocess (pps melange.ppx reason-react-ppx)))
> EOF

$ cp input.re.in input.re
$ chmod u+w input.re
$ dune build @mel
$ cat _build/default/output/input.js
// Generated by Melange
'use strict';

const Caml_option = require("melange.js/caml_option.js");
const JsxRuntime = require("react/jsx-runtime");

const first = JsxRuntime.jsx("div", {
className: "first"
});

const second = JsxRuntime.jsx("div", {
id: "second"
});

const ordinaryData = JsxRuntime.jsx("object", {
data: "file",
datatype: "text"
});

function optional(className, param) {
let tmp = {};
if (className !== undefined) {
tmp.className = Caml_option.valFromOption(className);
}
return JsxRuntime.jsx("div", tmp);
}

const renamed = JsxRuntime.jsx("div", {
"aria-activedescendant": "descendant",
"aria-label": "label",
as: "button",
open: true,
type: "button",
begin: "0",
end: "1",
in: "source",
to: "target"
});

const withChildren = JsxRuntime.jsxs("div", {
children: [
JsxRuntime.jsx("span", {}),
JsxRuntime.jsx("span", {})
]
}, "parent");

function withRefAndEvent(elementRef, handleClick) {
return JsxRuntime.jsx("button", {
ref: elementRef,
onClick: handleClick
});
}

function optionalKey(key, param) {
return JsxRuntime.jsx("div", {}, key !== undefined ? Caml_option.valFromOption(key) : undefined);
}

function Input$Component(Props) {
let dataFoo = Props.dataFoo;
return JsxRuntime.jsx("div", {
children: dataFoo
});
}

const Component = {
make: Input$Component
};

const component = JsxRuntime.jsx(Input$Component, {
dataFoo: "component"
});

function Input$IntegerComponent(Props) {
let dataFoo = Props.dataFoo;
return JsxRuntime.jsx("div", {
children: dataFoo
});
}

const IntegerComponent = {
make: Input$IntegerComponent
};

const integerComponent = JsxRuntime.jsx(Input$IntegerComponent, {
dataFoo: 42
});

const effects = JsxRuntime.jsx("div", {
className: next("class"),
id: next("id")
});

const effectfulUnit = JsxRuntime.jsx("div", (nextUnit(), {
className: "unit"
}));

module.exports = {
first,
second,
ordinaryData,
optional,
renamed,
withChildren,
withRefAndEvent,
optionalKey,
Component,
component,
IntegerComponent,
integerComponent,
effects,
effectfulUnit,
}
/* first Not a pure module */

Ordinary prop types are checked.

$ cat > input.re <<EOF
> let element = <div className=42 />;
> EOF
$ dune build @mel
File "input.re", line 1, characters 29-31:
1 | let element = <div className=42 />;
^^
Error: The constant 42 has type int but an expression was expected of type
string
[1]

Optional ordinary prop types are checked too.

$ cat > input.re <<EOF
> let element = <div className=?Some(42) />;
> EOF
$ dune build @mel
File "input.re", line 1, characters 35-37:
1 | let element = <div className=?Some(42) />;
^^
Error: The constant 42 has type int but an expression was expected of type
string
[1]

Renamed props retain their original types.

$ cat > input.re <<EOF
> let element = <div open_="yes" />;
> EOF
$ dune build @mel
File "input.re", line 1, characters 25-30:
1 | let element = <div open_="yes" />;
^^^^^
Error: This constant has type string but an expression was expected of type
bool
[1]

Unknown props fail. Show only the final diagnostic because the constructor's
list of valid props is long, while checking the compiler's exit status separately.

$ cat > input.re <<EOF
> let element = <div clasName="typo" />;
> EOF
$ dune build @mel > error.log 2>&1
[1]
$ tail -n 1 error.log
This argument cannot be applied with label ~clasName

Components must declare their dataFoo prop.

$ cat > input.re <<EOF
> module Component = {
> [@react.component]
> let make = () => React.null;
> };
> let element = <Component dataFoo="x" />;
> EOF
$ dune build @mel
File "input.re", line 5, characters 33-36:
5 | let element = <Component dataFoo="x" />;
^^^
Error: The function applied to this argument has type
?key:string -> < > Js.t
This argument cannot be applied with label ~dataFoo
[1]

Event handlers and refs retain their types.

$ cat > input.re <<EOF
> let element = <div onClick={event => event + 1} />;
> EOF
$ dune build @mel
File "input.re", line 1, characters 37-42:
1 | let element = <div onClick={event => event + 1} />;
^^^^^
Error: The value event has type
React.Event.Mouse.t = React.Event.Mouse.tag React.Event.synthetic
but an expression was expected of type int
[1]

$ cat > input.re <<EOF
> let element = <div ref=42 />;
> EOF
$ dune build @mel
File "input.re", line 1, characters 23-25:
1 | let element = <div ref=42 />;
^^
Error: The constant 42 has type int but an expression was expected of type
ReactDOM.domRef
[1]
Loading