squint

m3tti 2025-05-01T16:06:28.140809Z

hey squinters anyone used playwright with squint? my current issue is that playwright is giving me errors if i try this

(require '["@playwright/test" :refer [test expect]])

(test "has title"
      (^:async fn [{:keys [page]}]
       (js-await (page.goto ""))
       (js-await (-> (expect page)
                     (.toHaveTitle #"/MyTest/")))))
Playwright complains that the first argument of the generated function has to be destructured. So squint generates this
test("has title", (async function (p__3) {....
but playwright wants that
test("has title", (async function ({ page }) {
Any way to get this working with squint or do i have to fiddle that somehow :D

borkdude 2025-05-01T16:26:32.357139Z

you can use ^:js to use js destructuring

❤️ 1
m3tti 2025-05-01T16:26:52.309639Z

Aaaah

m3tti 2025-05-01T17:06:52.582719Z

is there a way to create a macro for this piece of code something like (deftest name body)

m3tti 2025-05-01T17:07:13.927379Z

i'm currently trying to get that somehow but i'm to dumb for macros i'm not that advanced yet 😄

m3tti 2025-05-01T17:33:23.262039Z

can anyone explain what i'm doing wrong 😞

(defmacro deftest [name bound & body]
  `(test ~name
         (^:async fn [^:js {:keys [page]}]
          (let [~bound page]
            ~@body))))
test is a function that is defined in a node library

✅ 1
m3tti 2025-05-02T07:47:15.693449Z

man now i get it why you should use macroexpand-1 😄 ok wrote my second real use macro thanx again @borkdude and i promise to not over use this stuff

🙌 1
🚀 2
2025-05-01T17:43:38.459549Z

what's the error?

m3tti 2025-05-01T17:44:28.291369Z

SyntaxError: /home/metti/code/staryou/node/e2e-tests/tests/ex.spec.mjs: Unexpected reserved word 'await'. (11:1)

   9 | clojure.core.test(squint_core.str("2. has title"), (function ({macros_SLASH_page}) {
  10 | const _STAR_page_STAR_1 = macros.page;
> 11 | (await _STAR_page_STAR_1.goto(""));
     |  ^
  12 | return (await expect(_STAR_page_STAR_1).toHaveTitle(/StarYou/));
  13 | ;;;
  14 | }));

   at ex.spec.mjs:11

   9 | clojure.core.test(squint_core.str("2. has title"), (function ({macros_SLASH_page}) {
  10 | const _STAR_page_STAR_1 = macros.page;
> 11 | (await _STAR_page_STAR_1.goto(""));
     | ^
  12 | return (await expect(_STAR_page_STAR_1).toHaveTitle(/StarYou/));
  13 | ;;;
  14 | }));

Error: No tests found

m3tti 2025-05-01T17:44:51.751439Z

and the funny part is why is it using clojure.core.test 😄

borkdude 2025-05-01T19:06:22.555649Z

test is a clojure.core function

borkdude 2025-05-01T19:08:17.354139Z

you probably want to do something like this:

(defmacro deftest [name bound & body]
  `(~'test ~name
    ((with-meta 'fn {:async true}) [~(with-meta '{:keys [page]} {:js true})]
     (let [~bound ~'page]
       ~@body))))
I think I might just switch to non-syntax-quote since you're basically fighting against auto-resolving here

m3tti 2025-05-01T19:09:35.791419Z

Whats the wit-meta doing?

m3tti 2025-05-01T19:10:24.296599Z

I guess i have to learn more about macros :/

borkdude 2025-05-01T19:14:47.486339Z

when you want to generate a symbol that has metadata from a macro you have to do it that way

m3tti 2025-05-01T19:16:28.079419Z

I just found the doc in the reader section interesting didn't know that. And non-syntax-quote means somthing like that (list test ~name ...) ?

borkdude 2025-05-01T19:17:14.724339Z

Usually you want to use list* so the varargs flattened into the list

(list* 'test .... body)

m3tti 2025-05-01T19:18:37.186769Z

Ah ok so i dont have to use ~@body right

borkdude 2025-05-01T19:19:03.849399Z

yes

m3tti 2025-05-01T19:19:32.619699Z

Ok this was great thank you so much @borkdude

m3tti 2025-05-01T21:15:14.406549Z

yay i did it but still not really a clue 😄 but it works that way

(defmacro deftest [name binding & body]
  (list 'test name
        (list 'fn [(with-meta '{:keys [page]} {:js true})]
              (let [binding 'page]
                (list 'Promise.all (into [] body))))))

borkdude 2025-05-01T21:16:20.887009Z

nice, perhaps you forgot the async metadata on fn though?

borkdude 2025-05-01T21:17:07.325949Z

the let expression also needs to be quoted

borkdude 2025-05-01T21:17:34.644069Z

it would probably help if you just wrote this as a function and inspected the output yourself in a REPL

borkdude 2025-05-01T21:17:52.460649Z

you can also print the metadata like this:

(binding [*print-meta* true] (pr-str expression))

borkdude 2025-05-01T21:18:40.668359Z

combined with:

(def expression (macroexpand-1 '(deftest ....)))
you may get what's failing

m3tti 2025-05-01T21:20:02.076879Z

here is a newer version

(defmacro deftest [name binding & body]
  (list 'test name
        (list (with-meta 'fn {:async true}) [(with-meta '{:keys [page]} {:js true})]
              (let [binding 'page]
                body
                nil))))
is there a more elegant way to skip the return?

m3tti 2025-05-01T21:20:42.865169Z

you mean nrepl with squint and do a macroexpand-1 right

borkdude 2025-05-01T21:20:45.775879Z

skip the return? what I mean is that you're not generating a let expression

borkdude 2025-05-01T21:21:05.513309Z

you can do this in a normal Clojure REPL, squint's REPL doesn't support this probably

borkdude 2025-05-01T21:21:09.976579Z

babashka / nbb do

borkdude 2025-05-01T21:22:18.709339Z

do you use clj-kondo?

borkdude 2025-05-01T21:22:58.164339Z

here you can see that the binding argument of the macro isn't used:

borkdude 2025-05-01T21:23:02.455479Z

which may already give you a clue

m3tti 2025-05-01T21:33:56.928229Z

so something like that right

(defmacro deftest [name binding & body]
  (list 'test name
        (list (with-meta 'fn {:async true}) [(with-meta '{:keys [page]} {:js true})]
              (list 'let (vector binding 'page)
                    (list* 'do body)))))
no 😄

borkdude 2025-05-01T21:34:12.648229Z

indeed

m3tti 2025-05-01T21:34:20.812719Z

heleluja

borkdude 2025-05-01T21:34:55.858969Z

now you compare this version with the syntax-quote and decide which one is worse :)

m3tti 2025-05-01T21:35:22.424339Z

so thats how a playwright test would look now

(deftest "2. has title" page
  (js-await (.goto page ""))
  (js-await (-> page
                expect
                (.toHaveTitle #"Hello World"))))

👍 1
m3tti 2025-05-01T21:35:29.328469Z

vs

m3tti 2025-05-01T21:37:40.374039Z

(test "3. has title"
      (^:async fn [^:js {:keys [page]}]
       (js-await (.goto page ""))
       (js-await (-> page
                     expect
                     (.toHaveTitle #"StarYou")))))