New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@eidos/ui-kit

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@eidos/ui-kit

  • 0.21.1
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
2
decreased by-90.91%
Maintainers
1
Weekly downloads
 
Created
Source

The Handle Object

The Handle Object system can be used to add "handle ID" attributes to the DOM so that they can be identified in automated browser testing. The Handle Object allows you to identify functionally important DOM elements in your tests using an alternative structural semantic scheme of your choice, rather than e.g. div > div > div > ul > li > div.

Use with React Components

Simple Handle

  1. Let your React component (optionally) accept a Handle object.
interface MyComponentProps {
  handle?: Handle;
}
  1. Spread the Handle object into React DOM Elements where the handle should go.
function MyComponent(props: MyComponentProps) {
  return <div {...props.handle} />;
}
  1. When mounting the component, pass a handle instance to Handle prop.
render(<MyComponent handle={createHandle()} />, document.getElementById("app"));

In the DOM, the div or MyComponent will receive a value for the data-handle-id attribute. Since our handle is simple, this attribute value will be "", signifying the root handle. This obviously is of very little practical use, so let us see how we can make something more useful by creating structural handles.

Structural Handle

Now we will create a handle with some structure inside it. Suppose our application is made of a ComponentA that internally has two instances of ComponentB.

function ComponentB() {
  return <div>I'm B</div>;
}

function ComponentA() {
  return (
    <div>
      I'm A, and I have two B's inside me:
      <ComponentB />
      <ComponentB />
    </div>
  );
}

Now we'll allow the wrapper div of ComponentB and that of ComponentA be identified with our handles. The Handle for ComponentB will be just like what we had with MyComponent: a simple Handle

interface ComponentBProps {
  handle?: Handle;
}

function ComponentB(props: ComponentBProps) {
  return <div {...props.handle}>I'm B</div>;
}

For ComponentA, however, we have a "structure": twice ComponentBs. We can define a type-parameterized Handled to declare this fact.

interface ComponentAShape {
  b1: {};
  b2: {};
}

interface ComponentAProps {
  handle?: Handle<ComponentAShape>;
}

function ComponentA(props: ComponentAProps) {
  return (
    <div {...props.handle}>
      I'm A, and I have two B's inside me:
      <ComponentB handle={props.handle?.b1} />
      <ComponentB handle={props.handle?.b2} />
    </div>
  );
}

Now, when mounting ComponentA as root, we will have the following elements receiving data-handle-id attributes:

  • The container div of ComponentA will receive "" (root handle)
  • The container div of the first ComponentB will receive "b1"
  • The container div of the second ComponentB will receive "b2"

Symbolic Querying

So now you can use something like the below to get back the DOM element in browser-based automated testing.

document.querySelector('[data-handle-id="b1"]');

Or better still, do it symbolically:

const rootHandle = createHandle<ComponentAShape>();
render(<MyComponent handle={rootHandle} />, document.getElementById("app"));

// ... Then later ...
document.querySelector(`[data-handle-id="${CSS.escape(rootHandle.b1)}"]`);

With Selenium Web Driver, you could do something like this (with aid of the css.escape module to allow CSS escaping in Node).

driver.findElement(By.css(CSS.escape(rootHandle.b1)));

Doing it symbolically is especially useful in TypeScript, as this plays well with IDEs such as VSCode offering to refactor-rename your handle shape interface properties: All names become traceable, you have single source of truth, and you can refactor with confidence!

Not Tied to React

Note that the use of Handle is not exclusive to React. Any componentized UI pattern can make use of it.

How does it work?

The Handle Object, created first by calling createHandle(), is an ES6 proxy object with a few special properties that allow them to be used to describe UI Element structures in a semantic that is aside from the literal DOM element hierarchy.

  1. It allows any property to be materialized into existence. With the exception of some "magic" properties (see later), all properties of a Handle is also a Handle.
const handle = createHandle(); // This is a handle
const foo = handle.foo; // This is also a handle
const bar = foo.bar; // This is also a handle
  1. A "sub-handle", that is a handle that is obtained by materializing a property of a "parent" handle, remembers its full path. This information can be obtained by getting the data-handle-id property, or, more strictly, the property encoded by the export HANDLE_ID_ATTRIBUTE
handle[HANDLE_ID_ATTRIBUTE]; // ""
foo[HANDLE_ID_ATTRIBUTE]; // "foo"
bar[HANDLE_ID_ATTRIBUTE]; // "foo:bar"
  1. A Handle object can be iterated (and therefore spread), in which case only the magic property HANDLE_ID_ATTRIBUTE will be iterated.
const spreadFoo = { ...foo }; // { [HANDLE_ID_ATTRIBUTE]: "foo" }
  1. In TypeScript, The createHandle accepts an optional type parameter describing the shape of the handle's structure; this can be used to limit the set of "allowed" properties that can be materialized.
const handle = createHandle<{ foo: {}; bar: { baz: {} } }>();
handle.foo; // OK
handle.bar; // OK
handle.baz; // Type Error, `baz` doesn't exist on `handle`.
handle.bar.baz; // OK

FAQs

Package last updated on 08 Mar 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc