Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal jest string fromat #3160

Closed
aaronabramov opened this issue Mar 16, 2017 · 12 comments
Closed

Universal jest string fromat #3160

aaronabramov opened this issue Mar 16, 2017 · 12 comments

Comments

@aaronabramov
Copy link
Contributor

The problem:
Jest needs to support different platforms when it prints its output (terminal, nuclide, html, terminal with no color support, snapshots)

There's a few ways we can implement that, but after our discussion with @kentaromiura we focused more on investigating some universal jest format.
Here's my thought on what it may look like:

  1. A jest-print-utils package that will export the following API:
type JestFormatedString = string;

type JestPrintUtils = {
  green: (input: string) => JestFormatedString,
  red: (input: string) => JestFormatedString,
  bold: (input: string) => JestFormatedString,
  dim: (input: string) => JestFormatedString,
 // ...
};

JestFormattedString type is jest a string that follows jest specific print format (a string with XML-like tags describing fonts)

Example:

import {red, green} from 'jest-print-utils';

const jestFormattedString = `hey, i'm ${green('green')}. and i'm ${red('red')}`;
console.log(jestFormattedString);
// hey i'm <JEST_GREEN_TAG_UUID>green</JEST_GREEN_TAG_UUID>. and i'm <JEST_RED_TAG_UUID>red</JEST_RED_TAG_UUID>

where UUID tags can be found in a common constant definition (to make sure they're unique and don't overlap with hmtl markup or similar)

JEST_UUID_TAGS: {
  RED: `RED_${uuid.gen()}`,
  GREEN: `GREEN_${uuid.gen()},
  // ...
}
  1. A jestFormattedString converters that can convert JestFormattedString type to any other string types (html, ASCII, strip tags completely, or something else)
    Example:
import {green, toHTML, toASCII, toNoColors, toSnapshotFormat} from 'jest-print-utils';

const str = `i'm ${green('green')}` // => 'i'm <JEST_GREEN_UUID>green</JEST_GREEN_UUID>

toHTML(str); // i'm <span style='color: green'>green</span>
toASCII(str); // i'm 0[m21green (or whatever the format is)
toNoColors(str) // i'm green
toSnapshotFormat(str) // i'm <green>green</green>

cc @kentaromiura @thymikee

@cpojer
Copy link
Member

cpojer commented Mar 17, 2017

A couple of thoughts:

  • Let's please not call it "util". I hate "util"s. I want to get rid of all the files and packages called "util" in Jest.
  • If we do this, we gotta stop using red and green and give semantic meaning to the way we format text. Instead of red, we should use error. This will also allow to change what that looks like in different places, like Nuclide.
  • I'm a bit worried that the end result here is a slightly more structured string format that we'll regex over to turn it from one format to another, the added value isn't actually that much. How about we start using JSX with different renderers? That seems to me like the best way to build a structured data format for Jest.

@thymikee
Copy link
Collaborator

Are we seriously considering JSX to format messages? If so, I think I could give it a try and implement this (after we settle this is actually a good idea).

I imagine formatting message like this:

const {JestFormat, Default, Error} = require('jest-format');
const jsx = <Default>Some <Error>text</Error> message</Default>;

Which then would go through Babel to output something like this:

const jsx = JestFormat.createElement(
  Default,
  null,
  'Some ',
  JestFormat.createElement(Error, null, 'text'),
  ' message',
);

Which would format to something like this:

JestFormat.createElement = function(type, props, children) {
  const result = {
    $$typeof: Symbol.for('JEST_FORMAT'),
    props,
    type: Default,
  };
  return result;
};

This way we could easily write recursive renderers for html, ansi, etc and custom ones for editors support, as they would need to deal with JSON only.

Let me know what you think @DmitriiAbramov @kentaromiura

@cpojer
Copy link
Member

cpojer commented Mar 20, 2017

Yeah I think this could work. We don't need React, we just needn't JSX with the @jsx pragma. Curious what this would look like.

@aaronabramov
Copy link
Contributor Author

that actually looks amazing. How will we send serialized objects to other processes though?

@thymikee
Copy link
Collaborator

A message will be JSON data after all, so it shouldn't be problematic.

@kentaromiura
Copy link
Contributor

As per Christoph suggestion, using the jsx pragma it will be possible to create a function like:

/** @jsx format */

const format = (type, _, ...parts) => {
  return {
    type,
    parts,
    [Symbol.for('custom-format')]: true
  }
}


var message = (
  <message>
    Error: expected value to be (using ===):
    <expected>"bar"</expected>
    Received:
    <received>"foo"</received>
  </message>
);

Then we could just feed pretty-format the most appropriate plugin to have that message output how we wants;
and example of the html render might be similar to this:

{
    test: x => x[Symbol.for('custom-format')],
    print: (val,print,opt,color) => (
      '<span class="jest-'+ val.type +'">' + val.parts.map(val => {
        if (typeof val === 'string') return val;
        return print(val, print, opt, color)
      }).join('') + '</span>')
}

https://jsfiddle.net/fjfuabya/

@aaronabramov
Copy link
Contributor Author

@kentaromiura that looks amazing!
we only need to fix the whitespace. but i think we can just add some padding to elements like <expected> and <received>

@thymikee
Copy link
Collaborator

Actually we could adjust whitespace and indentation in props:

<message indent={1}>
    Error: expected value to be (using ===):
    <expected indent={1}>"bar"</expected>
    Received:
    <received indent={1}>"foo"</received>
</message>

Also, it's going to be a ton of work to change all the messages 😐

@aaronabramov
Copy link
Contributor Author

and what about newlines? :)
how to we tell

this is <green>green</green>

from

this is
<green>green</green>

@brigand
Copy link
Contributor

brigand commented Apr 12, 2017

I don't think there's any way to detect the new line from code.

/* @jsx h */
<div>
  foo
  bar
</div>
/* @jsx h */
h(
  "div",
  null,
  "foo bar"
);

Could have a <linebreak> or {'\n'}.

@github-actions
Copy link

This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days.

@github-actions github-actions bot added the Stale label Feb 26, 2022
@SimenB
Copy link
Member

SimenB commented Feb 27, 2022

Almost 5 years without movement, I think we can close this (doing something like #7910 makes more sense to me, and if that ever happens, it would unblock doing the work discussed heree)

@SimenB SimenB closed this as completed Feb 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants