Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@khanacademy/wonder-blocks-link

Package Overview
Dependencies
Maintainers
1
Versions
302
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@khanacademy/wonder-blocks-link - npm Package Compare versions

Comparing version 3.3.1 to 3.4.0

components/__tests__/link.flowtest.js

1

__tests__/custom-snapshot.test.js

@@ -36,2 +36,3 @@ // @flow

pressed: state === "pressed",
waiting: false,
};

@@ -38,0 +39,0 @@ test(`kind:${kind} href:${href} light:${String(

@@ -8,81 +8,339 @@ // @flow

const wait = (delay: number = 0) =>
new Promise((resolve, reject) => {
// eslint-disable-next-line no-restricted-syntax
return setTimeout(resolve, delay);
});
describe("Link", () => {
beforeEach(() => {
// Note: window.location.assign needs a mock function in the testing
// environment.
window.location.assign = jest.fn();
unmountAll();
});
test("client-side navigation", () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link testId="link" href="/foo">
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
afterEach(() => {
window.location.assign.mockClear();
});
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {button: 0});
describe("client-side navigation", () => {
test("works for known URLs", () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link testId="link" href="/foo">
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Assert
expect(wrapper.find("#foo").exists()).toBe(true);
});
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {button: 0});
test("client-side navigation with unknown URL fails", () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link testId="link" href="/unknown">
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Assert
expect(wrapper.find("#foo").exists()).toBe(true);
});
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {button: 0});
test("navigation to without route does not render", () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link testId="link" href="/unknown">
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Assert
expect(wrapper.find("#foo").exists()).toBe(false);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {button: 0});
// Assert
expect(wrapper.find("#foo").exists()).toBe(false);
});
test("waits until beforeNav resolves before navigating", async () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.resolve()}
>
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
await wait(0);
wrapper.update();
// Assert
expect(wrapper.find("#foo")).toExist();
});
test("doesn't navigate before beforeNav resolves", async () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.resolve()}
>
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
// Assert
expect(wrapper.find("#foo")).not.toExist();
});
test("does not navigate if beforeNav rejects", async () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.reject()}
>
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
await wait(0);
wrapper.update();
// Assert
expect(wrapper.find("#foo")).not.toExist();
});
test("runs safeWithNav if set", async () => {
// Arrange
const safeWithNavMock = jest.fn();
const wrapper = mount(
<MemoryRouter>
<div>
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.resolve()}
safeWithNav={safeWithNavMock}
>
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
await wait(0);
wrapper.update();
// Assert
expect(safeWithNavMock).toHaveBeenCalled();
});
test("doesn't run safeWithNav until beforeNav resolves", () => {
// Arrange
const safeWithNavMock = jest.fn();
const wrapper = mount(
<MemoryRouter>
<div>
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.resolve()}
safeWithNav={safeWithNavMock}
>
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
// Assert
expect(safeWithNavMock).not.toHaveBeenCalled();
});
});
test("client-side navigation with `skipClientNav` set to `true` fails", () => {
// Arrange
const wrapper = mount(
<MemoryRouter>
<div>
<Link testId="link" href="/foo" skipClientNav>
Click me!
</Link>
<Switch>
<Route path="/foo">
<div id="foo">Hello, world!</div>
</Route>
</Switch>
</div>
</MemoryRouter>,
);
describe("full page load navigation", () => {
test("doesn't redirect if safeWithNav hasn't resolved yet when skipClientNav=true", () => {
// Arrange
jest.spyOn(window.location, "assign").mockImplementation(() => {});
const wrapper = mount(
<Link
testId="link"
href="/foo"
safeWithNav={() => Promise.resolve()}
skipClientNav={true}
>
Click me!
</Link>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {button: 0});
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
// Assert
expect(wrapper.find("#foo").exists()).toBe(false);
// Assert
expect(window.location.assign).not.toHaveBeenCalled();
});
test("redirects after safeWithNav resolves when skipClientNav=true", async () => {
// Arrange
jest.spyOn(window.location, "assign").mockImplementation(() => {});
const wrapper = mount(
<Link
testId="link"
href="/foo"
safeWithNav={() => Promise.resolve()}
skipClientNav={true}
>
Click me!
</Link>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
await wait(0);
wrapper.update();
// Assert
expect(window.location.assign).toHaveBeenCalledWith("/foo");
});
test("redirects after beforeNav and safeWithNav resolve when skipClientNav=true", async () => {
// Arrange
jest.spyOn(window.location, "assign").mockImplementation(() => {});
const wrapper = mount(
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.resolve()}
safeWithNav={() => Promise.resolve()}
skipClientNav={true}
>
Click me!
</Link>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
await wait(0);
wrapper.update();
// Assert
expect(window.location.assign).toHaveBeenCalledWith("/foo");
});
test("doesn't redirect before beforeNav resolves when skipClientNav=true", () => {
// Arrange
jest.spyOn(window.location, "assign").mockImplementation(() => {});
const wrapper = mount(
<Link
testId="link"
href="/foo"
beforeNav={() => Promise.resolve()}
skipClientNav={true}
>
Click me!
</Link>,
);
// Act
const buttonWrapper = wrapper.find(`[data-test-id="link"]`).first();
buttonWrapper.simulate("click", {
button: 0,
});
// Assert
expect(window.location.assign).not.toHaveBeenCalled();
});
});
});

@@ -43,2 +43,3 @@ // @flow

testId,
waiting: _,
...handlers

@@ -45,0 +46,0 @@ } = this.props;

@@ -103,2 +103,19 @@ // @flow

onClick?: (e: SyntheticEvent<>) => mixed,
/**
* Run async code before navigating to the URL passed to `href`. If the
* promise returned rejects then navigation will not occur.
*
* If both safeWithNav and beforeNav are provided, beforeNav will be run
* first and safeWithNav will only be run if beforeNav does not reject.
*/
beforeNav?: () => Promise<mixed>,
/**
* Run async code in the background while client-side navigating. If the
* browser does a full page load navigation, the callback promise must be
* settled before the navigation will occur. Errors are ignored so that
* navigation is guaranteed to succeed.
*/
safeWithNav?: () => Promise<mixed>,
|};

@@ -135,2 +152,4 @@

onClick,
beforeNav,
safeWithNav,
href,

@@ -151,5 +170,7 @@ skipClientNav,

disabled={false}
onClick={onClick}
href={href}
role="link"
onClick={onClick}
beforeNav={beforeNav}
safeWithNav={safeWithNav}
>

@@ -156,0 +177,0 @@ {(state, handlers) => {

13

dist/es/index.js

@@ -242,3 +242,4 @@ import { createElement, Component } from 'react';

testId = _this$props.testId,
handlers = _objectWithoutProperties(_this$props, ["caret", "children", "skipClientNav", "focused", "hovered", "href", "kind", "light", "visitable", "pressed", "style", "testId"]);
_ = _this$props.waiting,
handlers = _objectWithoutProperties(_this$props, ["caret", "children", "skipClientNav", "focused", "hovered", "href", "kind", "light", "visitable", "pressed", "style", "testId", "waiting"]);

@@ -363,6 +364,8 @@ var router = this.context.router;

onClick = _this$props.onClick,
beforeNav = _this$props.beforeNav,
safeWithNav = _this$props.safeWithNav,
href = _this$props.href,
skipClientNav = _this$props.skipClientNav,
children = _this$props.children,
sharedProps = _objectWithoutProperties(_this$props, ["onClick", "href", "skipClientNav", "children"]);
sharedProps = _objectWithoutProperties(_this$props, ["onClick", "beforeNav", "safeWithNav", "href", "skipClientNav", "children"]);

@@ -372,5 +375,7 @@ var ClickableBehavior = getClickableBehavior(href, skipClientNav, this.context.router);

disabled: false,
href: href,
role: "link",
onClick: onClick,
href: href,
role: "link"
beforeNav: beforeNav,
safeWithNav: safeWithNav
}, function (state, handlers) {

@@ -377,0 +382,0 @@ return /*#__PURE__*/createElement(LinkCore, _extends({}, sharedProps, state, handlers, {

@@ -226,3 +226,4 @@ module.exports =

testId = _this$props.testId,
handlers = _objectWithoutProperties(_this$props, ["caret", "children", "skipClientNav", "focused", "hovered", "href", "kind", "light", "visitable", "pressed", "style", "testId"]);
_ = _this$props.waiting,
handlers = _objectWithoutProperties(_this$props, ["caret", "children", "skipClientNav", "focused", "hovered", "href", "kind", "light", "visitable", "pressed", "style", "testId", "waiting"]);

@@ -384,6 +385,8 @@ var router = this.context.router;

onClick = _this$props.onClick,
beforeNav = _this$props.beforeNav,
safeWithNav = _this$props.safeWithNav,
href = _this$props.href,
skipClientNav = _this$props.skipClientNav,
children = _this$props.children,
sharedProps = link_objectWithoutProperties(_this$props, ["onClick", "href", "skipClientNav", "children"]);
sharedProps = link_objectWithoutProperties(_this$props, ["onClick", "beforeNav", "safeWithNav", "href", "skipClientNav", "children"]);

@@ -393,5 +396,7 @@ var ClickableBehavior = Object(wonder_blocks_core_["getClickableBehavior"])(href, skipClientNav, this.context.router);

disabled: false,
href: href,
role: "link",
onClick: onClick,
href: href,
role: "link"
beforeNav: beforeNav,
safeWithNav: safeWithNav
}, function (state, handlers) {

@@ -398,0 +403,0 @@ return /*#__PURE__*/external_react_["createElement"](link_core_LinkCore, link_extends({}, sharedProps, state, handlers, {

{
"name": "@khanacademy/wonder-blocks-link",
"version": "3.3.1",
"version": "3.4.0",
"design": "v1",

@@ -18,4 +18,4 @@ "publishConfig": {

"dependencies": {
"@khanacademy/wonder-blocks-color": "^1.1.12",
"@khanacademy/wonder-blocks-core": "^2.5.2"
"@khanacademy/wonder-blocks-color": "^1.1.13",
"@khanacademy/wonder-blocks-core": "^2.6.0"
},

@@ -31,3 +31,3 @@ "peerDependencies": {

},
"gitHead": "a2b5548f5d7db108c39961071d081ec5d96fa88f"
"gitHead": "65c91a0dcf5f6f6e3b235d40bab721ddfdd4f5cf"
}
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