Categories
plugins WordPress

Beginner’s Guide to WordPress Plugin Development

The WordPress CMS has changed the face of our Internet and allowed a surge of new ideas to prosper, and its open-source movement holds a strong presence rooted in software and web development….

Visit hongkiat.com for full content.
Source: hongkiat

Categories
3D Printing Graphics

50 Sites to Download Free 3D Models – Best Of

3D printers have immensely revolutionized the art and manufacturing industry. With advancements in the 3D printer technology, it is now not very difficult to own one, even in your home or office….

Visit hongkiat.com for full content.
Source: hongkiat

Categories
Uncategorized

How To Test Your React Apps With The React Testing Library

How To Test Your React Apps With The React Testing Library

How To Test Your React Apps With The React Testing Library

Chidi Orji

2020-07-03T12:30:00+00:00
2020-07-05T00:11:03+00:00

Today, we’ll briefly discuss why it’s important to write automated tests for any software project, and shed light on some of the common types of automated testing. We’ll build a to-do list app by following the Test-Driven Development (TDD) approach. I’ll show you how to write both unit and functional tests, and in the process, explain what code mocks are by mocking a few libraries. I’ll be using a combination of RTL and Jest — both of which come pre-installed in any new project created with Create-React-App (CRA).

To follow along, you need to know how to set up and navigate a new React project and how to work with the yarn package manager (or npm). Familiarities with Axios and React-Router are also required.

Best Practices With React

React is a fantastic JavaScript library for building rich user interfaces. It provides a great component abstraction for organizing your interfaces into well-functioning code, and there’s just about anything you can use it for. Read more articles on React →

Why You Should Test Your Code

Before shipping your software to end-users, you first have to confirm that it is working as expected. In other words, the app should satisfy its project specifications.

Just as it is important to test our project as a whole before shipping it to end-users, it’s also essential to keep testing our code during the lifetime of a project. This is necessary for a number of reasons. We may make updates to our application or refactor some parts of our code. A third-party library may undergo a breaking change. Even the browser that is running our web application may undergo breaking changes. In some cases, something stops working for no apparent reason — things could go wrong unexpectedly. Thus, it is necessary to test our code regularly for the lifetime of a project.

Broadly speaking, there are manual and automated software tests. In a manual test, a real user performs some action on our application to verify that they work correctly. This kind of test is less reliable when repeated several times because it’s easy for the tester to miss some details between test runs.

In an automated test, however, a test script is executed by a machine. With a test script, we can be sure that whatever details we set in the script will remain unchanged on every test run.

This kind of test gives us the benefits of being predictable and fast, such that we can quickly find and fix bugs in our code.

Having seen the necessity of testing our code, the next logical question is, what sort of automated tests should we write for our code? Let’s quickly go over a few of them.

Types Of Automated Testing

There are many different types of automated software testing. Some of the most common ones are unit tests, integration tests, functional tests, end-to-end tests, acceptance tests, performance tests, and smoke tests.

  1. Unit test
    In this kind of test, the goal is to verify that each unit of our application, considered in isolation, is working correctly. An example would be testing that a particular function returns an expected value, give some known inputs. We’ll see several examples in this article.
  2. Smoke test
    This kind of test is done to check that the system is up and running. For example, in a React app, we could just render our main app component and call it a day. If it renders correctly we can be fairly certain that our app would render on the browser.
  3. Integration test
    This sort of test is carried out to verify that two or more modules can work well together. For example, you might run a test to verify that your server and database are actually communicating correctly.
  4. Functional test
    A functional test exists to verify that the system meets its functional specification. We’ll see an example later.
  5. End-to-end test
    This kind of test involves testing the application the same way it would be used in the real world. You can use a tool like cypress for E2E tests.
  6. Acceptance test
    This is usually done by the business owner to verify that the system meets specifications.
  7. Performance test
    This sort of testing is carried out to see how the system performs under significant load. In frontend development, this is usually about how fast the app loads on the browser.

There’s more here if you’re interested.

Why Use React Testing Library?

When it comes to testing React applications, there are a few testing options available, of which the most common ones I know of are Enzyme and React Testing Library (RTL).

RTL is a subset of the @testing-library family of packages. Its philosophy is very simple. Your users don’t care whether you use redux or context for state management. They care less about the simplicity of hooks nor the distinction between class and functional components. They just want your app to work in a certain way. It is, therefore, no surprise that the testing library’s primary guiding principle is

“The more your tests resemble the way your software is used, the more confidence they can give you.”

So, whatever you do, have the end-user in mind and test your app just as they would use it.

Choosing RTL gives you a number of advantages. First, it’s much easier to get started with it. Every new React project bootstrapped with CRA comes with RTL and Jest configured. The React docs also recommend it as the testing library of choice. Lastly, the guiding principle makes a lot of sense — functionality over implementation details.

With that out of the way, let’s get started with building a to-do list app, following the TDD approach.

Project Setup

Open a terminal and copy and run the below command.

# start new react project and start the server
npx create-react-app start-rtl && cd start-rtl && yarn start

This should create a new React project and start the server on http://localhost:3000. With the project running, open a separate terminal, run yarn test and then press a. This runs all tests in the project in watch mode. Running the test in watch mode means that the test will automatically re-run when it detects a change in either the test file or the file that is being tested. On the test terminal, you should see something like the picture below:

Initial test passing

Initial test passing. (Large preview)

You should see a lot of greens, which indicates that the test we’re running passed in flying colors.

As I mentioned earlier, CRA sets up RTL and Jest for every new React project. It also includes a sample test. This sample test is what we just executed.

When you run the yarn test command, react-scripts calls upon Jest to execute the test. Jest is a JavaScript testing framework that’s used in running tests. You won’t find it listed in package.json but you can do a search inside yarn.lock to find it. You can also see it in node_modules/.

Jest is incredible in the range of functionality that it provides. It provides tools for assertions, mocking, spying, etc. I strongly encourage you to take at least a quick tour of the documentation. There’s a lot to learn there that I cannot scratch in this short piece. We’ll be using Jest a lot in the coming sections.

Open package.json let’s see what we have there. The section of interest is dependencies.

  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    ...
  },

We have the following packages installed specifically for testing purpose:

  1. @testing-library/jest-dom: provides custom DOM element matchers for Jest.
  2. @testing-library/react: provides the APIs for testing React apps.
  3. @testing-library/user-event: provides advanced simulation of browser interactions.

Open up App.test.js let’s take a look at its content.

import React from 'react';
import { render } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  const { getByText } = render();
  const linkElement = getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

The render method of RTL renders the <App /> component and returns an object which is de-structured for the getByText query. This query finds elements in the DOM by their display text. Queries are the tools for finding elements in the DOM. The complete list of queries can be found here. All of the queries from the testing library are exported by RTL, in addition to the render, cleanup, and act methods. You can read more about these in the API section.

The text is matched with the regular expression /learn react/i. The i flag makes the regular expression case-insensitive. We expect to find the text Learn React in the document.

All of this mimics the behavior a user would experience in the browser when interacting with our app.

Let’s start making the changes required by our app. Open App.js and replace the content with the below code.

import React from "react";
import "./App.css";
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <h2>Getting started with React testing library</h2>
      </header>
    </div>
  );
}
export default App;

If you still have the test running, you should see the test fail. Perhaps you can guess why that is the case, but we’ll return to it a bit later. Right now I want to refactor the test block.

Replace the test block in src/App.test.js with the code below:

# use describe, it pattern
describe("<App />", () => {
  it("Renders <App /> component correctly", () => {
    const { getByText } = render(<App />);
    expect(getByText(/Getting started with React testing library/i)).toBeInTheDocument();
  });
});

This refactor makes no material difference to how our test will run. I prefer the describe and it pattern as it allows me structure my test file into logical blocks of related tests. The test should re-run and this time it will pass. In case you haven’t guessed it, the fix for the failing test was to replace the learn react text with Getting started with React testing library.

In case you don’t have time to write your own styles you can just copy the one below into App.css.

.App {
  min-height: 100vh;
  text-align: center;
}
.App-header {
  height: 10vh;
  display: flex;
  background-color: #282c34;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}
.App-body {
  width: 60%;
  margin: 20px auto;
}
ul {
  padding: 0;
  display: flex;
  list-style-type: decimal;
  flex-direction: column;
}
li {
  font-size: large;
  text-align: left;
  padding: 0.5rem 0;
}
li a {
  text-transform: capitalize;
  text-decoration: none;
}
.todo-title {
  text-transform: capitalize;
}
.completed {
  color: green;
}
.not-completed {
  color: red;
}

You should already see the page title move up after adding this CSS.

I consider this a good point for me to commit my changes and push to Github. The corresponding branch is 01-setup.

Let’s continue with our project setup. We know we’re going to need some navigation in our app so we need React-Router. We’ll also be making API calls with Axios. Let’s install both.

# install react-router-dom and axios
yarn add react-router-dom axios

Most React apps you’ll build will have to maintain state. There’s a lot of libraries available for managing state. But for this tutorial, I’ll be using React’s context API and the useContext hook. So let’s set up our app’s context.

Create a new file src/AppContext.js and enter the below content.

import React from "react";
export const AppContext = React.createContext({});

export const AppProvider = ({ children }) => {
  const reducer = (state, action) => {
    switch (action.type) {
      case "LOAD_TODOLIST":
        return { ...state, todoList: action.todoList };
      case "LOAD_SINGLE_TODO":
        return { ...state, activeToDoItem: action.todo };
      default:
        return state;
    }
  };
  const [appData, appDispatch] = React.useReducer(reducer, {
    todoList: [],
    activeToDoItem: { id: 0 },
  });
  return (
    <AppContext.Provider value={{ appData, appDispatch }}>
      {children}
    </AppContext.Provider>
  );
};

Here we create a new context with React.createContext({}), for which the initial value is an empty object. We then define an AppProvider component that accepts children component. It then wraps those children in AppContext.Provider, thus making the { appData, appDispatch } object available to all children anywhere in the render tree.

Our reducer function defines two action types.

  1. LOAD_TODOLIST which is used to update the todoList array.
  2. LOAD_SINGLE_TODO which is used to update activeToDoItem.

appData and appDispatch are both returned from the useReducer hook. appData gives us access to the values in the state while appDispatch gives us a function which we can use to update the app’s state.

Now open index.js, import the AppProvider component and wrap the <App /> component with <AppProvider />. Your final code should look like what I have below.

import { AppProvider } from "./AppContext";

ReactDOM.render(
  <React.StrictMode>
    <AppProvider>
      <App />
    </AppProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

Wrapping <App /> inside <AppProvider /> makes AppContext available to every child component in our app.

Remember that with RTL, the aim is to test our app the same way a real user would interact with it. This implies that we also want our tests to interact with our app state. For that reason, we also need to make our <AppProvider /> available to our components during tests. Let’s see how to make that happen.

The render method provided by RTL is sufficient for simple components that don’t need to maintain state or use navigation. But most apps require at least one of both. For this reason, it provides a wrapper option. With this wrapper, we can wrap the UI rendered by the test renderer with any component we like, thus creating a custom render. Let’s create one for our tests.

Create a new file src/custom-render.js and paste the following code.

import React from "react";
import { render } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";

import { AppProvider } from "./AppContext";

const Wrapper = ({ children }) => {
  return (
    <AppProvider>
      <MemoryRouter>{children}</MemoryRouter>
    </AppProvider>
  );
};

const customRender = (ui, options) =>
  render(ui, { wrapper: Wrapper, ...options });

// re-export everything
export * from "@testing-library/react";

// override render method
export { customRender as render };

Here we define a <Wrapper /> component that accepts some children component. It then wraps those children inside <AppProvider /> and <MemoryRouter />. MemoryRouter is

A <Router> that keeps the history of your “URL” in memory (does not read or write to the address bar). Useful in tests and non-browser environments like React Native.

We then create our render function, providing it the Wrapper we just defined through its wrapper option. The effect of this is that any component we pass to the render function is rendered inside <Wrapper />, thus having access to navigation and our app’s state.

The next step is to export everything from @testing-library/react. Lastly, we export our custom render function as render, thus overriding the default render.

Note that even if you were using Redux for state management the same pattern still applies.

Let’s now make sure our new render function works. Import it into src/App.test.js and use it to render the <App /> component.

Open App.test.js and replace the import line. This

import { render } from '@testing-library/react';

should become

import { render } from './custom-render';

Does the test still pass? Good job.

There’s one small change I want to make before wrapping up this section. It gets tiring very quickly to have to write const { getByText } and other queries every time. So, I’m going to be using the screen object from the DOM testing library henceforth.

Import the screen object from our custom render file and replace the describe block with the code below.

import { render, screen } from "./custom-render";

describe("<App />", () => {
  it("Renders <App /> component correctly", () => {
    render(<App />);
    expect(
      screen.getByText(/Getting started with React testing library/i)
    ).toBeInTheDocument();
  });
});

We’re now accessing the getByText query from the screen object. Does your test still pass? I’m sure it does. Let’s continue.

If your tests don’t pass you may want to compare your code with mine. The corresponding branch at this point is 02-setup-store-and-render.

Testing And Building The To-Do List Index Page

In this section, we’ll pull to-do items from http://jsonplaceholder.typicode.com/. Our component specification is very simple. When a user visits our app homepage,

  1. show a loading indicator that says Fetching todos while waiting for the response from the API;
  2. display the title of 15 to-do items on the screen once the API call returns (the API call returns 200). Also, each item title should be a link that will lead to the to-do details page.

Following a test-driven approach, we’ll write our test before implementing the component logic. Before doing that we’ll need to have the component in question. So go ahead and create a file src/TodoList.js and enter the following content:

import React from "react";
import "./App.css";
export const TodoList = () => {
  return (
    <div>
    </div>
  );
};

Since we know the component specification we can test it in isolation before incorporating it into our main app. I believe it’s up to the developer at this point to decide how they want to handle this. One reason you might want to test a component in isolation is so that you don’t accidentally break any existing test and then having to fight fires in two locations. With that out of the way let’s now write the test.

Create a new file src/TodoList.test.js and enter the below code:

import React from "react";
import axios from "axios";
import { render, screen, waitForElementToBeRemoved } from "./custom-render";
import { TodoList } from "./TodoList";
import { todos } from "./makeTodos";

describe("<App />", () => {
  it("Renders <TodoList /> component", async () => {
    render(<TodoList />);
    await waitForElementToBeRemoved(() => screen.getByText(/Fetching todos/i));

    expect(axios.get).toHaveBeenCalledTimes(1);
    todos.slice(0, 15).forEach((td) => {
      expect(screen.getByText(td.title)).toBeInTheDocument();
    });
  });
});

Inside our test block, we render the <TodoList /> component and use the waitForElementToBeRemoved function to wait for the Fetching todos text to disappear from the screen. Once this happens we know that our API call has returned. We also check that an Axios get call was fired once. Finally, we check that each to-do title is displayed on the screen. Note that the it block receives an async function. This is necessary for us to be able to use await inside the function.

Each to-do item returned by the API has the following structure.

{
  id: 0,
  userId: 0,
  title: 'Some title',
  completed: true,
}

We want to return an array of these when we

import { todos } from "./makeTodos"

The only condition is that each id should be unique.

Create a new file src/makeTodos.js and enter the below content. This is the source of todos we’ll use in our tests.

const makeTodos = (n) => {
  // returns n number of todo items
  // default is 15
  const num = n || 15;
  const todos = [];
  for (let i = 0; i < num; i++) {
    todos.push({
      id: i,
      userId: i,
      title: `Todo item ${i}`,
      completed: [true, false][Math.floor(Math.random() * 2)],
    });
  }
  return todos;
};

export const todos = makeTodos(200);

This function simply generates a list of n to-do items. The completed line is set by randomly choosing between true and false.

Unit tests are supposed to be fast. They should run within a few seconds. Fail fast! This is one of the reasons why letting our tests make actual API calls is impractical. To avoid this we mock such unpredictable API calls. Mocking simply means replacing a function with a fake version, thus allowing us to customize the behavior. In our case, we want to mock the get method of Axios to return whatever we want it to. Jest already provides mocking functionality out of the box.

Let’s now mock Axios so it returns this list of to-dos when we make the API call in our test. Create a file src/__mocks__/axios.js and enter the below content:

import { todos } from "../makeTodos";

export default {
  get: jest.fn().mockImplementation((url) => {
    switch (url) {
      case "https://jsonplaceholder.typicode.com/todos":
        return Promise.resolve({ data: todos });
      default:
        throw new Error(`UNMATCHED URL: ${url}`);
    }
  }),
};

When the test starts, Jest automatically finds this mocks folder and instead of using the actual Axios from node_modules/ in our tests, it uses this one. At this point, we’re only mocking the get method using Jest’s mockImplementation method. Similarly, we can mock other Axios methods like post, patch, interceptors, defaults etc. Right now they’re all undefined and any attempt to access, axios.post for example, would result in an error.

Note that we can customize what to return based on the URL the Axios call receives. Also, Axios calls return a promise which resolves to the actual data we want, so we return a promise with the data we want.

At this point, we have one passing test and one failing test. Let’s implement the component logic.

Open src/TodoList.js let’s build out the implementation piece by piece. Start by replacing the code inside with this one below.

import React from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import "./App.css";
import { AppContext } from "./AppContext";

export const TodoList = () => {
  const [loading, setLoading] = React.useState(true);
  const { appData, appDispatch } = React.useContext(AppContext);

  React.useEffect(() => {
    axios.get("https://jsonplaceholder.typicode.com/todos").then((resp) => {
      const { data } = resp;
      appDispatch({ type: "LOAD_TODOLIST", todoList: data });
      setLoading(false);
    });
  }, [appDispatch, setLoading]);

  return (
    <div>
      // next code block goes here
    </div>
  );
};

We import AppContext and de-structure appData and appDispatch from the return value of React.useContext. We then make the API call inside a useEffect block. Once the API call returns, we set the to-do list in state by firing the LOAD_TODOLIST action. Finally, we set the loading state to false to reveal our to-dos.

Now enter the final piece of code.

{loading ? (
  <p>Fetching todos</p>
) : (
  <ul>
    {appData.todoList.slice(0, 15).map((item) => {
      const { id, title } = item;
      return (
        <li key={id}>
          <Link to={`/item/${id}`} data-testid={id}>
            {title}
          </Link>
        </li>
      );
    })}
  </ul>
)}

We slice appData.todoList to get the first 15 items. We then map over those and render each one in a <Link /> tag so we can click on it and see the details. Note the data-testid attribute on each Link. This should be a unique ID that will aid us in finding individual DOM elements. In a case where we have similar text on the screen, we should never have the same ID for any two elements. We’ll see how to use this a bit later.

My tests now pass. Does yours pass? Great.

Let’s now incorporate this component into our render tree. Open up App.js let’s do that.

First things. Add some imports.

import { BrowserRouter, Route } from "react-router-dom";
import { TodoList } from "./TodoList";

We need BrowserRouter for navigation and Route for rendering each component in each navigation location.

Now add the below code after the <header /> element.

<div className="App-body">
  <BrowserRouter>
    <Route exact path="/" component={TodoList} />
  </BrowserRouter>
</div>

This is simply telling the browser to render the <TodoList /> component when we’re on the root location, /. Once this is done, our tests still pass but you should see some error messages on your console telling you about some act something. You should also see that the <TodoList /> component seems to be the culprit here.

Terminal showing act warnings

Terminal showing act warnings. (Large preview)

Since we’re sure that our TodoList component by itself is okay, we have to look at the App component, inside of which is rendered the <TodoList /> component.

This warning may seem complex at first but it is telling us that something is happening in our component that we’re not accounting for in our test. The fix is to wait for the loading indicator to be removed from the screen before we proceed.

Open up App.test.js and update the code to look like so:

import React from "react";
import { render, screen, waitForElementToBeRemoved } from "./custom-render";
import App from "./App";
describe("<App />", () => {
  it("Renders <App /> component correctly", async () => {
    render(<App />);
    expect(
      screen.getByText(/Getting started with React testing library/i)
    ).toBeInTheDocument();
    await waitForElementToBeRemoved(() => screen.getByText(/Fetching todos/i));
  });
});

We’ve made two changes. First, we changed the function in the it block to an async function. This is a necessary step to allow us to use await in the function body. Secondly, we wait for the Fetching todos text to be removed from the screen. And voila!. The warning is gone. Phew! I strongly advise that you bookmark this post by Kent Dodds for more on this act warning. You’re gonna need it.

Now open the page in your browser and you should see the list of to-dos. You can click on an item if you like, but it won’t show you anything because our router doesn’t yet recognize that URL.

For comparison, the branch of my repo at this point is 03-todolist.

Let’s now add the to-do details page.

Testing And Building The Single To-Do Page

To display a single to-do item we’ll follow a similar approach. The component specification is simple. When a user navigates to a to-do page:

  1. display a loading indicator that says Fetching todo item id where id represents the to-do’s id, while the API call to https://jsonplaceholder.typicode.com/todos/item_id runs.
  2. When the API call returns, show the following information:
    • Todo item title
    • Added by: userId
    • This item has been completed if the to-do has been completed or
    • This item is yet to be completed if the to-do has not been completed.

Let’s start with the component. Create a file src/TodoItem.js and add the following content.

import React from "react";
import { useParams } from "react-router-dom";

import "./App.css";

export const TodoItem = () => {
  const { id } = useParams()
  return (
    <div className="single-todo-item">
    </div>
  );
};

The only thing new to us in this file is the const { id } = useParams() line. This is a hook from react-router-dom that lets us read URL parameters. This id is going to be used in fetching a to-do item from the API.

This situation is a bit different because we’re going to be reading the id from the location URL. We know that when a user clicks a to-do link, the id will show up in the URL which we can then grab using the useParams() hook. But here we’re testing the component in isolation which means that there’s nothing to click, even if we wanted to. To get around this we’ll have to mock react-router-dom, but only some parts of it. Yes. It’s possible to mock only what we need to. Let’s see how it’s done.

Create a new mock file src/__mocks__ /react-router-dom.js. Now paste in the following code:

module.exports = {
  ...jest.requireActual("react-router-dom"),
  useParams: jest.fn(),
};

By now you should have noticed that when mocking a module we have to use the exact module name as the mock file name.

Here, we use the module.exports syntax because react-router-dom has mostly named exports. (I haven’t come across any default export since I’ve been working with it. If there are any, kindly share with me in the comments). This is unlike Axios where everything is bundled as methods in one default export.

We first spread the actual react-router-dom, then replace the useParams hook with a Jest function. Since this function is a Jest function, we can modify it anytime we want. Keep in mind that we’re only mocking the part we need to because if we mock everything, we’ll lose the implementation of MemoryHistory which is used in our render function.

Let’s start testing!

Now create src/TodoItem.test.js and enter the below content:

import React from "react";
import axios from "axios";
import { render, screen, waitForElementToBeRemoved } from "./custom-render";
import { useParams, MemoryRouter } from "react-router-dom";
import { TodoItem } from "./TodoItem";

describe("<TodoItem />", () => {
  it("can tell mocked from unmocked functions", () => {
    expect(jest.isMockFunction(useParams)).toBe(true);
    expect(jest.isMockFunction(MemoryRouter)).toBe(false);
  });
});

Just like before, we have all our imports. The describe block then follows. Our first case is only there as a demonstration that we’re only mocking what we need to. Jest’s isMockFunction can tell whether a function is mocked or not. Both expectations pass, confirming the fact that we have a mock where we want it.

Add the below test case for when a to-do item has been completed.

  it("Renders <TodoItem /> correctly for a completed item", async () => {
    useParams.mockReturnValue({ id: 1 });
    render(<TodoItem />);

    await waitForElementToBeRemoved(() =>
      screen.getByText(/Fetching todo item 1/i)
    );

    expect(axios.get).toHaveBeenCalledTimes(1);
    expect(screen.getByText(/todo item 1/)).toBeInTheDocument();
    expect(screen.getByText(/Added by: 1/)).toBeInTheDocument();
    expect(
      screen.getByText(/This item has been completed/)
    ).toBeInTheDocument();
  });

The very first thing we do is to mock the return value of useParams. We want it to return an object with an id property, having a value of 1. When this is parsed in the component, we end up with the following URL https://jsonplaceholder.typicode.com/todos/1. Keep in mind that we have to add a case for this URL in our Axios mock or it will throw an error. We will do that in just a moment.

We now know for sure that calling useParams() will return the object { id: 1 } which makes this test case predictable.

As with previous tests, we wait for the loading indicator, Fetching todo item 1 to be removed from the screen before making our expectations. We expect to see the to-do title, the id of the user who added it, and a message indicating the status.

Open src/__mocks__/axios.js and add the following case to the switch block.

      case "https://jsonplaceholder.typicode.com/todos/1":
        return Promise.resolve({
          data: { id: 1, title: "todo item 1", userId: 1, completed: true },
        });

When this URL is matched, a promise with a completed to-do is returned. Of course, this test case fails since we’re yet to implement the component logic. Go ahead and add a test case for when the to-do item has not been completed.

  it("Renders <TodoItem /> correctly for an uncompleted item", async () => {
    useParams.mockReturnValue({ id: 2 });
    render(<TodoItem />);
    await waitForElementToBeRemoved(() =>
      screen.getByText(/Fetching todo item 2/i)
    );
    expect(axios.get).toHaveBeenCalledTimes(2);
    expect(screen.getByText(/todo item 2/)).toBeInTheDocument();
    expect(screen.getByText(/Added by: 2/)).toBeInTheDocument();
    expect(
      screen.getByText(/This item is yet to be completed/)
    ).toBeInTheDocument();
  });

This is the same as the previous case. The only difference is the ID of the to-do, the userId, and the completion status. When we enter the component, we’ll need to make an API call to the URL https://jsonplaceholder.typicode.com/todos/2. Go ahead and add a matching case statement to the switch block of our Axios mock.

case "https://jsonplaceholder.typicode.com/todos/2":
  return Promise.resolve({
    data: { id: 2, title: "todo item 2", userId: 2, completed: false },
  });

When the URL is matched, a promise with an uncompleted to-do is returned.

Both test cases are failing. Now let’s add the component implementation to make them pass.

Open src/TodoItem.js and update the code to the following:

import React from "react";
import axios from "axios";
import { useParams } from "react-router-dom";
import "./App.css";
import { AppContext } from "./AppContext";

export const TodoItem = () => {
  const { id } = useParams();
  const [loading, setLoading] = React.useState(true);
  const {
    appData: { activeToDoItem },
    appDispatch,
  } = React.useContext(AppContext);

  const { title, completed, userId } = activeToDoItem;
  React.useEffect(() => {
    axios
      .get(`https://jsonplaceholder.typicode.com/todos/${id}`)
      .then((resp) => {
        const { data } = resp;
        appDispatch({ type: "LOAD_SINGLE_TODO", todo: data });
        setLoading(false);
      });
  }, [id, appDispatch]);
  return (
    <div className="single-todo-item">
      // next code block goes here.
    </div>
  );
};

As with the <TodoList /> component, we import AppContext. We read activeTodoItem from it, then we read the to-do title, userId, and completion status. After that we make the API call inside a useEffect block. When the API call returns we set the to-do in state by firing the LOAD_SINGLE_TODO action. Finally, we set our loading state to false to reveal the to-do details.

Let’s add the final piece of code inside the return div:

{loading ? (
  <p>Fetching todo item {id}</p>
) : (
  <div>
    <h2 className="todo-title">{title}</h2>
    <h4>Added by: {userId}</h4>
    {completed ? (
      <p className="completed">This item has been completed</p>
    ) : (
      <p className="not-completed">This item is yet to be completed</p>
    )}
  </div>
)}

Once this is done all tests should now pass. Yay! We have another winner.

Our component tests now pass. But we still haven’t added it to our main app. Let’s do that.

Open src/App.js and add the import line:

import { TodoItem } from './TodoItem'

Add the TodoItem route above the TodoList route. Be sure to preserve the order shown below.

# preserve this order
<Route path="/item/:id" component={TodoItem} />
<Route exact path="/" component={TodoList} />

Open your project in your browser and click on a to-do. Does it take you to the to-do page? Of course, it does. Good job.

In case you’re having any problem, you can check out my code at this point from the 04-test-todo branch.

Phew! This has been a marathon. But bear with me. There’s one last point I’d like us to touch. Let’s quickly have a test case for when a user visits our app, and then proceed to click on a to-do link. This is a functional test to mimic how our app should work. In practice, this is all the testing we need to be done for this app. It ticks every box in our app specification.

Open App.test.js and add a new test case. The code is a bit long so we’ll add it in two steps.

import userEvent from "@testing-library/user-event";
import { todos } from "./makeTodos";

jest.mock("react-router-dom", () => ({
  ...jest.requireActual("react-router-dom"),
}));

describe("<App />"
  ...
  // previous test case
  ...

  it("Renders todos, and I can click to view a todo item", async () => {
    render(<App />);
    await waitForElementToBeRemoved(() => screen.getByText(/Fetching todos/i));
    todos.slice(0, 15).forEach((td) => {
      expect(screen.getByText(td.title)).toBeInTheDocument();
    });
    // click on a todo item and test the result
    const { id, title, completed, userId } = todos[0];
    axios.get.mockImplementationOnce(() =>
      Promise.resolve({
        data: { id, title, userId, completed },
      })
    );
    userEvent.click(screen.getByTestId(String(id)));
    await waitForElementToBeRemoved(() =>
      screen.getByText(`Fetching todo item ${String(id)}`)
    );

    // next code block goes here
  });
});

We have two imports of which userEvent is new. According to the docs,

user-event is a companion library for the React Testing Library that provides a more advanced simulation of browser interactions than the built-in fireEvent method.”

Yes. There is a fireEvent method for simulating user events. But userEvent is what you want to be using henceforth.

Before we start the testing process, we need to restore the original useParams hooks. This is necessary since we want to test actual behavior, so we should mock as little as possible. Jest provides us with requireActual method which returns the original react-router-dom module.

Note that we must do this before we enter the describe block, otherwise, Jest would ignore it. It states in the documentation that requireActual:

“…returns the actual module instead of a mock, bypassing all checks on whether the module should receive a mock implementation or not.”

Once this is done, Jest bypasses every other check and ignores the mocked version of the react-router-dom.

As usual, we render the <App /> component and wait for the Fetching todos loading indicator to disappear from the screen. We then check for the presence of the first 15 to-do items on the page.

Once we’re satisfied with that, we grab the first item in our to-do list. To prevent any chance of a URL collision with our global Axios mock, we override the global mock with Jest’s mockImplementationOnce. This mocked value is valid for one call to the Axios get method. We then grab a link by its data-testid attribute and fire a user click event on that link. Then we wait for the loading indicator for the single to-do page to disappear from the screen.

Now finish the test by adding the below expectations in the position indicated.

expect(screen.getByText(title)).toBeInTheDocument();
expect(screen.getByText(`Added by: ${userId}`)).toBeInTheDocument();
switch (completed) {
  case true:
    expect(
      screen.getByText(/This item has been completed/)
    ).toBeInTheDocument();
    break;
  case false:
    expect(
      screen.getByText(/This item is yet to be completed/)
    ).toBeInTheDocument();
    break;
  default:
    throw new Error("No match");
    }
  

We expect to see the to-do title and the user who added it. Finally, since we can’t be sure about the to-do status, we create a switch block to handle both cases. If a match is not found we throw an error.

You should have 6 passing tests and a functional app at this point. In case you’re having trouble, the corresponding branch in my repo is 05-test-user-action.

Conclusion

Phew! That was some marathon. If you made it to this point, congratulations. You now have almost all you need to write tests for your React apps. I strongly advise that you read CRA’s testing docs and RTL’s documentation. Overall both are relatively short and direct.

I strongly encourage you to start writing tests for your React apps, no matter how small. Even if it’s just smoke tests to make sure your components render. You can incrementally add more test cases over time.

Smashing Editorial
(ks, ra, yk, il)

Source: smash mag

Categories
Community & Inspiration diversity in tech diversity in web design ethnic minorities who code girls who code women who code

Diversity Initiatives in Web Design

Web developers have been the bedrock of any company’s business strategy for some time, and the industry is continuing to thrive and grow at a rapid pace. This is why it’s surprising that it is so lacklustre when it comes to diversity.

A recent study revealed 80% of those in the design industry are male, and more specifically 79% within the field of web design. According to WISE, just 23% of the people working in STEM roles (Science, Technology, Engineering and Maths) are female and women currently account for just 15.8% of the UK’s current generation of engineering and technology graduates.

Why the Lack of Diversity in Web Design?

The main reason for this, as cited by the Organisation for Economic Co-operation and Development (OECD) found that women still lack the confidence to pursue these careers, despite their school results being as good as (or better) than their male counterparts. Research has found that the professional and technical services sector has the fourth-highest gender pay gap of all UK industries. If more women were to join these higher-paid sectors it could help reduce the gender pay gap as a whole, as well as help female economic empowerment.

This division is seen in ethnic minority groups too. The numbers for BAME (Black, Asian, Minority Ethnic) employees in the British tech industry are unknown but is estimated by the British Computer Society to be at 1-2%, a ridiculously low number in this day and age. This is why groups and organisations are cropping up designed to promote an industry that reflects all of society rather than one part of it. Here are some of the organisations to pay attention to who are bridging the diversity gaps in web design.

Girls Who Code

Girls Who Code are working to create opportunities for women within tech, aiming to deepen their computer science skills and confidence. They run a range of programs designed to equip women with the necessary computing skills to pursue opportunities in the field and to give chances that are often shunned due to society. Founder Saujani states that women are socialized to seek perfection, and this is something that needs to be overcome. One way to break that mentality at an early age, she says, is coding:

[Girls] walk into these classrooms and they feel like they will never be good at it, and when they learn how to create something, whether it’s a website or app, it changes their mindset and they stop giving up

Adobe Design Circle

Adobe Design Circle is another initiative aiming to introduce all members of society to design. They want to create more visibility for design as a viable career path for anyone that might be considering it, and to help with youth entering the field. This is opening the opportunities of working in tech and web to aspiring designers at a young age who aren’t necessarily yet conditioned by the pressures of society and showing them it can be a realistic career path.

They have their own scholarships and mentoring initiative to support these goals too. The faces behind the team of Adobe Design Circle range through multiple ethnicities and have a fairly even male-female divide. This equal representation alone is inspiring. One of Adobe’s core missions is to offer youth the opportunity to learn and express themselves through creativity and technology, regardless of their economic or cultural backgrounds. With this they specifically encourage applicants of all backgrounds to apply and offer many other opportunities from mentoring to internships.

Ladies that UX

Ladies that UX are a collaborative community of women in UX aiming to “support each other, push the UX boundaries and promote female skill and talent.” It is a European-based initiative where each city involved runs slightly different events and groups decide together what they would like to get from their meetups. They assist each other with UX challenges, discuss topics, and brainstorm ideas. Ladies that UX was created in 2013 by Georgie Bottomley and Lizzie Dyson with the aim of bringing together women in the industry, offering support and creating connections around the world.

Xuntos

Xuntos is aiming to create the largest community of ambitious and talented individuals from under-represented groups in the technology industry. It works to nurture university students and recent graduates that are often overlooked in the tech industry by the means of educational workshops, university hubs, events and an active community. The very name “Xuntos” is a Galician word which means “together” and this is their most important factor. They want people to realise they are not alone and just because the representation isn’t there, doesn’t mean their capabilities aren’t.

Colorintech

Colorintech is a non-profit organisation that was founded in 2016. It aims to close the gap and shorten the learning curve, with a strong community designed to help each other. The company was founded by Silicon Valley tech executive Dion McKenzie and ex-Googler Ashleigh Ainsley after they became frustrated at the few black individuals in the field. Since its inception 30,000 students, professionals, volunteers and tech companies have been impacted by their work, and over 450 minorities graduated from their programs in 2019 alone.

UKBlackTech

UKBlackTech are on a mission to create the most diverse tech sector in the world. Their aim is to encourage more ethnic minorities to enter the UK’s technology workforce and make an impact. To help with this, they design and implement different initiatives to help them get employed and retain employment, put on bespoke events that target aspects such as specific job roles or tech topics and promote different opportunities for members to apply to.

Witty Careers

Witty Careers was created with the aim to support women from black and ethnic minority backgrounds in the UK and equip them with the skills to build a career in the tech industry. They run different practical skills workshops and events which in the past have included visits to a Microsoft store, Uber, and Pivotal. They open doors for communications, networking and future career prospects for those in the minority. They also have a handy range of resources designed to help you get into the career you want. From CV writing advice to industry insights, they are all free of charge.

 

Featured image via Unsplash.

Source

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Source: Web Designer Depot

Categories
Uncategorized

Collective #612



60 Days of Animation

The Undead Institute offers books on HTML, CSS, Responsive Design and more that marry humor, excellent teaching, and brain-lodging practice for an experience that’ll outlive the apocalypse.

Check it out




Stryve

A new community for tech enthusiasts to share, learn, and build their careers.

Check it out


The design systems between us

Ethan Marcotte shares his thoughts on why he believes that design systems haven’t brought rich, cross-functional collaboration to most organizations.

Read it









Profiled

With Profiled you can create a developer portfolio from your GitHub account.

Check it out


Is WebP really better than JPEG?

According to Google, WebP is 25 – 34% smaller than JPEG at equivalent quality. But how much of it is really true? Find out in this article by Johannes Siipola.

Read it









The post Collective #612 appeared first on Codrops.


Source: codrops

Categories
E-Commerce Invoicing and Accounting

20 Free Invoice Generators to Create Invoices Instantly

As a small business owner or a freelancer, you know the importance of invoicing. Invoices are sent to notify your clients about products and services you delivered, so you can get paid for your work….

Visit hongkiat.com for full content.
Source: hongkiat

Categories
Uncategorized

Differences Between Static Generated Sites And Server-Side Rendered Apps

Differences Between Static Generated Sites And Server-Side Rendered Apps

Differences Between Static Generated Sites And Server-Side Rendered Apps

Timi Omoyeni

2020-07-02T12:00:00+00:00
2020-07-05T00:11:03+00:00

JavaScript currently has three types of applications that you can build with: Single Page Applications (SPAs), pre-rendering/static generated sites and server-side rendered applications. SPAs come with many challenges, one of which is Search Engine Optimization (SEO). Possible solutions are to make use of Static Site Generators or Server-Side Rendering (SSR).

In this article, I’m going to explain them alongside listing their pros and cons so you have a balanced view. We’re going to look at what static generated/pre-rendering is as well as frameworks such as Gatsby and VuePress that help in creating statically generated sites. We’re also going to look at what server-side rendered (SSR) applications are as well as frameworks like Nextjs and Nuxtjs that can help you create SSR applications. Finally, we’re going to cover the differences between these two methods and which of them you should use when building your next application.

Note: You can find all the code snippets in this article on GitHub.

What Is A Static Site Generator?

A Static Site Generator (SSG) is a software application that creates HTML pages from templates or components and a given content source. You give it some text files and content, and the generator will give you back a complete website, and this completed website is referred to as a static generated site. What this means is that your site pages are generated at build time and your site content does not change unless you add new contents or components and “rebuild” or you have to rebuild your site if you want it to be updated with new content.

Diagram explaining how static site generation works

How static site generation works (Large preview)

This approach is good for building applications that the content does not change too often — sites that the content does not have to change depending on the user, and sites that do not have a lot of user-generated content. An example of such a site is a blog or a personal website. Let’s look at some advantages of using static generated sites.

PROS

  • Fast website: Since all of your site’s pages and content have been generated at build time, you do not have to worry about API calls to the server for content and this makes your site very fast.
  • Easy to deploy: After your static site has been generated, you would be left with static files, and hence, it can be easily deployed to platforms like Netlify.
  • Security: Static generated site are solely composed of static files, the risk of being vulnerable to cyber attacks is minimal. This is because static generated sites have no database, attackers cannot inject malicious code or exploit your database.
  • You can use version control software (e.g git) to manage and track changes to your content. This can come in handy when you want to roll back changes you made to the content on your site.

CONS

  • Content can become stale if it changes too quickly.
  • To update its content, you have to rebuild the site.
  • Build time would increase depending on the size of the application.

Examples of static site generators are GatsbyJS and VuePress. Let us take a look at how to create static sites using these two generators.

Gatsby

According to their official website,

“Gatsby is a free and open-source framework based on React that helps developers build blazing-fast websites and apps.”

This means developers familiar with React would find it easy to get started with Gatsby.

To use this generator, you first have to install it using NPM:

npm install -g gatsby-cli

This will install Gatsby globally on your machine, you only have to run this command once on your machine. After this installation is complete, you can create your first static site generator using the following command.

gatsby new demo-gatsby

This command will create a new Gatsby project that I have named demo-gatsby. When this is done, you can start up your app server by running the following command:

cd demo-gatsby
gatsby develop

Your Gatsby application should be running on localhost:8000.

Gatsby default landing page

Gatsby default starter page (Large preview)

The folder structure for this app looks like this;

--| gatsby-browser.js  
--| LICENSE        
--| README.md
--| gatsby-config.js
--| node_modules/  
--| src/
----| components
----| pages
----| images
--| gatsby-node.js     
--| package.json   
--| yarn.lock
--| gatsby-ssr.js      
--| public/
----| icons
----| page-data
----| static

For this tutorial, we’re only going to look at the src/pages folder. This folder contains files that would be generated into routes on your site.

To test this, let us add a new file (newPage.js) to this folder:

import React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
import SEO from "../components/seo"
const NewPage = () => (
  <Layout>
    <SEO title="My New Page" />
    <h1>Hello Gatsby</h1>
    <p>This is my first Gatsby Page</p>
    <button>
      <Link to='/'>Home</Link>
    </button>
  </Layout>
)
export default NewPage

Here, we import React from the react package so when your code is transpiled to pure JavaScript, references to React will appear there. We also import a Link component from gatsby and this is one of React’s route tag that is used in place of the native anchor tag ( <a href='#'>Link</a>). It accepts a to prop that takes a route as a value.

We import a Layout component that was added to your app by default. This component handles the layout of pages nested inside it. We also import the SEO component into this new file. This component accepts a title prop and configures this value as part of your page’s metadata. Finally, we export the function NewPage that returns a JSX containing your new page’s content.

And in your index.js file, add a link to this new page we just created:

import React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"
const IndexPage = () => (
  <Layout>
    <SEO title="Home" />
    <h1>Hi people</h1>
    <p>Welcome to your new Gatsby site.</p>
    <p>Now go build something great.</p>
    <div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
      <Image />
    </div>
    <Link to="/page-2/">Go to page 2</Link>
    {/* new link */}
    <button>
      <Link to="/newPage/">Go to New Page</Link>
    </button>
  </Layout>
)
export default IndexPage

Here, we import the same components that were used in newPage.js file and they perform the same function in this file. We also import an Image component from our components folder. This component is added by default to your Gatsby application and it helps in lazy loading images and serving reduced file size. Finally, we export a function IndexPage that returns JSX containing our new link and some default content.

Now, if we open our browser, we should see our new link at the bottom of the page.

Gatsby default landing page with link to a new page

Gatsby landing page with new link (Large preview)

And if you click on Go To New Page, it should take you to your newly added page.

New page containing some texts

New gatsby page (Large preview)

VuePress

VuePress is a static site generator that is powered by Vue, Vue Router and Webpack. It requires little to no configuration for you to get started with it. While there are a number of tools that are static site generators, VuePress stands out from amongst the pack for a single reason: its primary directive is to make it easier for developers to create and maintain great documentation for their projects.

To use VuePress, you first have to install it:

//globally
yarn global add vuepress # OR npm install -g vuepress

//in an existing project
yarn add -D vuepress # OR npm install -D vuepress

Once the installation process is done, you can run the following command in your terminal:

# create the project folder
mkdir demo-vuepress && cd demo-vuepress

# create a markdown file
echo '# Hello VuePress' > README.md

# start writing
vuepress dev

Here, we create a folder for our VuePress application, add a README.md file with # Hello VuePress as the only content inside this file, and finally, start up our server.

When this is done, our application should be running on localhost:8080 and we should see this in our browser:

A VuePress webpage with a text saying ‘Hello VuePress’

VuePress landing page (Large preview)

VuePress supports VueJS syntax and markup inside this file. Update your README.md file with the following:

# Hello VuePress
_VuePress Rocks_
> **Yes!**
_It supports JavaScript interpolation code_
> **{{new Date()}}**
<p v-for="i of ['v','u', 'e', 'p', 'r', 'e', 's', 's']">{{i}}</p>

If you go back to your browser, your page should look like this:

Updated VuePress page

Updated Vuepress page (Large preview)

To add a new page to your VuePress site, you add a new markdown file to the root directory and name it whatever you want the route to be. In this case, I’ve gone ahead to name it Page-2.md and added the following to the file:

# hello World
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.

And now, if you navigate to /page-2 in your browser, we should see this:

A VuePress webpage containing hello world

A “Hello World” page in VuePress (Large preview)

What Is Server-Side Rendering? (SSR)

Server-Side Rendering (SSR), is the process of displaying web-pages on the server and passing it to the browser/client-side instead of rendering it in the browser. Server-side sends a fully rendered page to the client; the client’s JavaScript bundle takes over and allows the SPA framework to operate.

This means if you have an application that is server-side rendered, your content is fetched on the server side and passed to your browser to display to your user. With client-side rendering it is different, you would have to navigate to that page first before it fetches data from your server meaning your user would have to wait for some seconds before they’re served with the content on that page. Applications that have SSR enabled are called Server-side rendered applications.

A diagram explaining how server-side rendering works

How SSR works (Large preview)

This approach is good for building complex applications that require user interaction, rely on a database, or where the content changes very often. This is because content on these sites changes very often and the users need to see the updated content as soon as they’re updated. It is also good for applications that have tailored content depending on who is viewing it and applications where you need to store user-specific data like email and user preference while also catering for SEO. An example of this is a large e-commerce platform or a social media site. Let us look at some of the advantages of server-side rendering your applications.

Pros

  • Content is up to date because it fetches content on the go;
  • Your site loads fast because it fetches its content on the server-side before rendering it to the user;
  • Since in SSR JavaScript is rendered server-side, your users’ devices have little relevance to the load time of your page and this leads to better performance.

CONS

  • More API calls to the server since they’re made per request;
  • Cannot deploy to a static CDN.

Further examples of frameworks that offer SSR are Next.js and Nuxt.js.

Next.js

Next.js is a React.js framework that helps in building static sites, server-side rendered applications, and so on. Since it was built on React, knowledge of React is required to use this framework.

To create a Next.js app, you need to run the following:

npm init next-app
# or
yarn create next-app

You would be prompted to choose a name your application, I have named my application demo-next. The next option would be to select a template and I’ve selected the Default starter app after which it begins to set up your app. When this is done, we can now start our application

cd demo-next
yarn dev 
# or npm run dev

Your application should be running on localhost:3000 and you should see this in your browser;

Default Nextjs landing page

Next.js landing page (Large preview)

The page that is being rendered can be found in pages/index.js so if you open this file and modify the JSX inside the Home function, it would reflect in your browser. Replace the JSX with this:

import Head from 'next/head'
export default function Home() {
  return (
    <div className="container">
      <Head>
        <title>Hello Next.js</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
        <h1 className="title">
          Welcome to <a href="https://nextjs.org">Next.js!</a>
        </h1>
        <p className='description'>Nextjs Rocks!</p>
      </main>
      <style jsx>{`
        main {
          padding: 5rem 0;
          flex: 1;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
        }
        .title a {
          color: #0070f3;
          text-decoration: none;
        }
        .title a:hover,
        .title a:focus,
        .title a:active {
          text-decoration: underline;
        }
        .title {
          margin: 0;
          line-height: 1.15;
          font-size: 4rem;
        }
        .title,
        .description {
          text-align: center;
        }
        .description {
          line-height: 1.5;
          font-size: 1.5rem;
        }
      `}</style>
      <style jsx global>{`
        html,
        body {
          padding: 0;
          margin: 0;
          font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
            Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue,
            sans-serif;
        }
        * {
          box-sizing: border-box;
        }
      `}</style>
    </div>
  )
}

In this file, we make use of Next.js Head component to set our page’s metadata title and favicon for this page. We also export a Home function that returns a JSX containing our page’s content. This JSX contains our Head component together with our main page’s content. It also contains two style tags, one for styling this page and the other for the global styling of the app.

Now, you should see that the content on your app has changed to this:

Nextjs landing page containing ‘welcome to Nextjs’ text

Updated landing page (Large preview)

Now if we want to add a new page to our app, we have to add a new file inside the /pages folder. Routes are automatically created based on the /pages folder structure, this means that if you have a folder structure that looks like this:

--| pages
----| index.js ==> '/'
----| about.js ==> '/about'
----| projects
------| next.js ==> '/projects/next'

So in your pages folder, add a new file and name it hello.js then add the following to it:

import Head from 'next/head'
export default function Hello() {
  return (
    <div>
       <Head>
        <title>Hello World</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className='container'>
        <h1 className='title'>
         Hello <a href="https://en.wikipedia.org/wiki/Hello_World_(film)">World</a>
        </h1>
        <p className='subtitle'>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatem provident soluta, sit explicabo impedit nobis accusantium? Nihil beatae, accusamus modi assumenda, optio omnis aliquid nobis magnam facilis ipsam eum saepe!</p>
      </main>
      <style jsx> {`
      
      .container {
        margin: 0 auto;
        min-height: 100vh;
        max-width: 800px;
        text-align: center;
      }
      .title {
        font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont,
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
        display: block;
        font-weight: 300;
        font-size: 100px;
        color: #35495e;
        letter-spacing: 1px;
      }
      .subtitle {
        font-weight: 300;
        font-size: 22px;
        color: #526488;
        word-spacing: 5px;
        padding-bottom: 15px;
      }
      `} </style>
    </div>
  )
}

This page is identical to the landing page we already have, we only changed the content and added new styling to the JSX. Now if we visit localhost:3000/hello, we should see our new page:

A Nextjs webpage containing ‘Hello world’

A “Hello World ” page in Next.js (Large preview)

Finally, we need to add a link to this new page on our index.js page, and to do this, we make use of Next’s Link component. To do that, we have to import it first.

# index.js
import Link from 'next/link'

#Add this to your JSX
<Link href='/hello'>
<Link href='/hello'>
  <a>Next</a>
</Link>

This link component is how we add links to pages created in Next in our application.

Now if we go back to our homepage and click on this link, it would take us to our /hello page.

Nuxt.js

According to their official documentation:

“Nuxt is a progressive framework based on Vue.js to create modern web applications. It is based on Vue.js official libraries (vue, vue-router and vuex) and powerful development tools (webpack, Babel and PostCSS). Nuxt’s goal is to make web development powerful and performant with a great developer experience in mind.”

It is based on Vue.js so that means Vue.js developers would find it easy getting started with it and knowledge of Vue.js is required to use this framework.

To create a Nuxt.js app, you need to run the following command in your terminal:

yarn create nuxt-app <project-name>
# or npx
npx create-nuxt-app <project-name>

This would prompt you to select a name along with some other options. I named mine demo-nuxt and selected default options for the other options. When this is done, you can open your app folder and open pages/index.vue. Every file in this folder file is turned into a route and so our landing page is controlled by index.vue file. So if you update it with the following:

<template>
  <div class="container">
    <div>
      <logo />
      <h1 class="title">
        Hello Nuxt
      </h1>
      <h2 class="subtitle">
        Nuxt.js ROcks!
      </h2>
      <div class="links">
        <a
          href="https://nuxtjs.org/"
          target="_blank"
          class="button--green"
        >
          Documentation
        </a>
        <a
          href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          class="button--grey"
        >
          GitHub
        </a>
      </div>
    </div>
  </div>
</template>
<script>
import Logo from '~/components/Logo.vue'
export default {
  components: {
    Logo
  }
}
</script>
<style>
.container {
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}
.title {
  font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  display: block;
  font-weight: 300;
  font-size: 100px;
  color: #35495e;
  letter-spacing: 1px;
}
.subtitle {
  font-weight: 300;
  font-size: 42px;
  color: #526488;
  word-spacing: 5px;
  padding-bottom: 15px;
}
.links {
  padding-top: 15px;
}
</style>

And run your application:

cd demo-nuxt
# start your applicatio
yarn dev # or npm run dev

Your application should be running on localhost:3000 and you should see this:

Default Nuxtjs landing page

Nuxt.js landing page (Large preview)

We can see that this page displays the content we added in to index.vue. The router structure works the same way Next.js router works; it renders every file inside /pages folder into a page. So let us add a new page (hello.vue) to our application.

<template>
  <div>
    <h1>Hello World!</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Id ipsa vitae tempora perferendis, voluptate a accusantium itaque vel ex, provident autem quod rem saepe ullam hic explicabo voluptas, libero distinctio?</p>
  </div>
</template>
<script>
export default {};
</script>
<style>
</style>

So if you open localhost:3000/hello, you should see your new page in your browser.

A Nuxtjs webpage containing ‘Hello World’

“Hello World” page in Nuxtjs (Large preview)

Taking A Closer Look At The Differences

Now that we have looked at both static-site generators and server-side rendering and how to get started with them by using some popular tools, let us look at the differences between them.

Static Sites Generators Server-Side Rendering
Can easily be deployed to a static CDN Cannot be deployed to a static CDN
Content and pages are generated at build time Content and pages are generated per request
Content can become stale quickly Content is always up to date
Fewer API calls since it only makes it at build time Makes API calls each time a new page is visited

Conclusion

We can see why it is so easy to think both static generated sites and server-side rendered applications are the same. Now that we know the differences between them are, I would advise that we try to learn more on how to build both static generated sites and server-side rendered applications in order to fully understand the differences between them.

Further Resources

Here are some useful links that are bound to help you get started in no time:

Smashing Editorial
(ks, ra, il)

Source: smash mag

Categories
Freelance Freelancers Invoicing and Accounting

Top 10 Invoicing & Accounting Tools For Freelancers

Freelancers usually handle many jobs at the same time and the client is not the only reason who drive a freelancer nuts. Being your own boss and manager means you are your own accountant as well….

Visit hongkiat.com for full content.
Source: hongkiat

Categories
Culture productivity tips productivity tools

99 Tech Life Hacks You Should Know

A life hack is a strategy, technique, trick or shortcut that can help make life easier – by speeding up efficiency, enhancing productivity and sometimes minimizing a source of annoyance with a…

Visit hongkiat.com for full content.
Source: hongkiat

Categories
animation gsap hover image menu Navigation Tutorials

Creating a Menu Image Animation on Hover

At Codrops, we love experimenting with playful hover effects. Back in 2018, we explored a set of fun hover animations for links. We called that Image Reveal Hover Effects and it shows how to make images appear with a fancy animation when hovering items of a menu. After seeing the fantastic portfolio of Marvin Schwaibold, I wanted to try this effect again on a larger menu and add that beautiful swing effect when moving the mouse. Using some filters, this can also be made more dramatic.

If you are interested in other similar effect, have a look at these:

So, today we’ll have a look at how to create this juicy image hover reveal animation:

Some Markup and Styling

We’ll use a nested structure for each menu item because we’ll have several text elements that will appear on page load and hover.

But we’ll not go into the text animation on load or the hover effect so what we are interested in here is how we’ll make the image appear for each item. The first thing I do when I want to make a certain effect is to write up the structure that I need using no JavaScript. So let’s take a look at that:

<a class="menu__item">
    <span class="menu__item-text">
        <span class="menu__item-textinner">Maria Costa</span>
    </span>
    <span class="menu__item-sub">Style Reset 66 Berlin</span>
    <!-- Markup for the image, inserted with JS -->
    <div class="hover-reveal">
        <div class="hover-reveal__inner">
            <div class="hover-reveal__img" style="background-image: url(img/1.jpg);"></div>
        </div>
    </div>
</a>

In order to construct this markup for the image, we need to save the source somewhere. We’ll use a data attribute on the menu__item, e.g. data-img="img/1.jpg". We’ll go into more detail later on.

Next, we’ll have some styling for it:

.hover-reveal {
    position: absolute;
    z-index: -1;
    width: 220px;
    height: 320px;
    top: 0;
    left: 0;
    pointer-events: none;
    opacity: 0;
}

.hover-reveal__inner {
    overflow: hidden;
}

.hover-reveal__inner,
.hover-reveal__img {
    width: 100%;
    height: 100%;
    position: relative;
}

.hover-reveal__img {
    background-size: cover;
    background-position: 50% 50%;
}

Any other styles that are specific to our effect (like the transforms) we’ll add dynamically.

Let’s take a look at the JavaScript.

The JavaScript

We’ll use GSAP and besides our hover animation, we’ll also use a custom cursor and smooth scrolling. For that we’ll use the smooth scroll library from the amazing folks of Locomotive, the Agency of the year. Since those are both optional and out of the scope of the menu effect we want to showcase, we’ll not be covering it here.

First things first: let’s preload all the images. For the purpose of this demo we are doing this on page load, but that’s optional.

Once that’s done, we can initialize the smooth scroll instance, the custom cursor and our Menu instance.

Here’s how the entry JavaScript file (index.js) looks like:

import Cursor from './cursor';
import {preloader} from './preloader';
import LocomotiveScroll from 'locomotive-scroll';
import Menu from './menu';

const menuEl = document.querySelector('.menu');

preloader('.menu__item').then(() => {
    const scroll = new LocomotiveScroll({el: menuEl, smooth: true});
    const cursor = new Cursor(document.querySelector('.cursor'));
    new Menu(menuEl);
});

Now, let’s create a class for the Menu (in menu.js):

import {gsap} from 'gsap';
import MenuItem from './menuItem';

export default class Menu {
    constructor(el) {
        this.DOM = {el: el};
        this.DOM.menuItems = this.DOM.el.querySelectorAll('.menu__item');
        this.menuItems = [];
        [...this.DOM.menuItems].forEach((item, pos) => this.menuItems.push(new MenuItem(item, pos, this.animatableProperties)));

        ...
    }
    ...
}

So far we have a reference to the main element (the menu <nav>
element) and the menu item elements. We’ll also create an array of our MenuItem instances. But let’s cover that bit in a moment.

What we’ll want to do now is to update the transform (both, X and Y translate) value as we move the mouse over the menu items. But we might as well want to update other properties. In our case we will additionally be updating the rotation and the CSS filter value (brightness). For that, let’s create an object that stores this configuration:

constructor(el) {
    ...

    this.animatableProperties = {
        tx: {previous: 0, current: 0, amt: 0.08},
        ty: {previous: 0, current: 0, amt: 0.08},
        rotation: {previous: 0, current: 0, amt: 0.08},
        brightness: {previous: 1, current: 1, amt: 0.08}
    };
}

With interpolation, we can achieve the smooth animation effect when moving the mouse. The “previous” and “current” values are the values we’ll be interpolating. The current value of one of these “animatable” properties will be one between these two values at a specific increment. The value of “amt” is the amount to interpolate. As an example, the following formula calculates our current translationX value:

this.animatableProperties.tx.previous = MathUtils.lerp(this.animatableProperties.tx.previous, this.animatableProperties.tx.current, this.animatableProperties.tx.amt);

Finally, we can show the menu items, which are hidden by default. This was just a little extra, and totally optional, but it’s definitely a nice add-on to reveal each item with a delay on page load.

constructor(el) {
    ...

    this.showMenuItems();
}
showMenuItems() {
    gsap.to(this.menuItems.map(item => item.DOM.textInner), {
        duration: 1.2,
        ease: 'Expo.easeOut',
        startAt: {y: '100%'},
        y: 0,
        delay: pos => pos*0.06
    });
}

That’s it for the Menu class. What we’ll be looking into next is how to create the MenuItem class together with some helper variables and functions.

So, let’s start by importing the GSAP library (which we will use to show and hide the images), some helper functions and the images inside our images folder.

Next, we need to get access to the mouse position at any given time, since the image will follow along its movement. We can update this value on “mousemove” . We will also cache its position so we can calculate its speed and movement direction for both, the X and Y axis.

Hence, that’s what we’ll have so far in the menuItem.js file:

import {gsap} from 'gsap';
import { map, lerp, clamp, getMousePos } from './utils';
const images = Object.entries(require('../img/*.jpg'));

let mousepos = {x: 0, y: 0};
let mousePosCache = mousepos;
let direction = {x: mousePosCache.x-mousepos.x, y: mousePosCache.y-mousepos.y};

window.addEventListener('mousemove', ev => mousepos = getMousePos(ev));

export default class MenuItem {
    constructor(el, inMenuPosition, animatableProperties) {
        ...
    }
    ...
}

An item will be passed its position/index in the menu (inMenuPosition) and the animatableProperties object described before. The fact that the “animatable” property values are shared and updated among the different menu items will make the movement and rotation of the images continuous.

Now, in order to be possible to show and hide the menu item image in a fancy way, we need to create that specific markup we’ve shown in the beginning and append it to the item. Remember, our menu item is this by default:

<a class="menu__item" data-img="img/3.jpg">
    <span class="menu__item-text"><span class="menu__item-textinner">Franklin Roth</span></span>
    <span class="menu__item-sub">Amber Convention London</span>
</a>

Let’s append the following structure to the item:

<div class="hover-reveal">
    <div class="hover-reveal__inner" style="overflow: hidden;">
        <div class="hover-reveal__img" style="background-image: url(pathToImage);">
        </div>
    </div>
</div>

The hover-reveal element will be the one moving as we move the mouse.
The hover-reveal__inner element together with the hover-reveal__img (the one with the background image) will be the ones that we can animate together to create fancy animations like reveal/unreveal effects.

layout() {
    this.DOM.reveal = document.createElement('div');
    this.DOM.reveal.className = 'hover-reveal';
    this.DOM.revealInner = document.createElement('div');
    this.DOM.revealInner.className = 'hover-reveal__inner';
    this.DOM.revealImage = document.createElement('div');
    this.DOM.revealImage.className = 'hover-reveal__img';
    this.DOM.revealImage.style.backgroundImage = `url(${images[this.inMenuPosition][1]})`;
    this.DOM.revealInner.appendChild(this.DOM.revealImage);
    this.DOM.reveal.appendChild(this.DOM.revealInner);
    this.DOM.el.appendChild(this.DOM.reveal);
}

And the MenuItem constructor completed:

constructor(el, inMenuPosition, animatableProperties) {
    this.DOM = {el: el};
    this.inMenuPosition = inMenuPosition;
    this.animatableProperties = animatableProperties;
    this.DOM.textInner = this.DOM.el.querySelector('.menu__item-textinner');
    this.layout();
    this.initEvents();
}

The last step is to initialize some events. We need to show the image when hovering the item and hide it when leaving the item.

Also, when hovering it we need to update the animatableProperties object properties, and make the image move, rotate and change its brightness as the mouse moves:

initEvents() {
    this.mouseenterFn = (ev) => {
        this.showImage();
        this.firstRAFCycle = true;
        this.loopRender();
    };
    this.mouseleaveFn = () => {
        this.stopRendering();
        this.hideImage();
    };
    
    this.DOM.el.addEventListener('mouseenter', this.mouseenterFn);
    this.DOM.el.addEventListener('mouseleave', this.mouseleaveFn);
}

Let’s now code the showImage and hideImage functions.

We can create a GSAP timeline for this. Let’s start by setting the opacity to 1 for the reveal element (the top element of that structure we’ve just created). Also, in order to make the image appear on top of all other menu items, let’s set the item’s z-index to a high value.

Next, we can animate the appearance of the image. Let’s do it like this: the image gets revealed to the right or left, depending on the mouse x-axis movement direction (which we have in direction.x). For this to happen, the image element (revealImage) needs to animate its translationX value to the opposite side of its parent element (revealInner element).
That’s basically it:

showImage() {
    gsap.killTweensOf(this.DOM.revealInner);
    gsap.killTweensOf(this.DOM.revealImage);
    
    this.tl = gsap.timeline({
        onStart: () => {
            this.DOM.reveal.style.opacity = this.DOM.revealInner.style.opacity = 1;
            gsap.set(this.DOM.el, {zIndex: images.length});
        }
    })
    // animate the image wrap
    .to(this.DOM.revealInner, 0.2, {
        ease: 'Sine.easeOut',
        startAt: {x: direction.x < 0 ? '-100%' : '100%'},
        x: '0%'
    })
    // animate the image element
    .to(this.DOM.revealImage, 0.2, {
        ease: 'Sine.easeOut',
        startAt: {x: direction.x < 0 ? '100%': '-100%'},
        x: '0%'
    }, 0);
}

To hide the image we just need to reverse this logic:

hideImage() {
    gsap.killTweensOf(this.DOM.revealInner);
    gsap.killTweensOf(this.DOM.revealImage);

    this.tl = gsap.timeline({
        onStart: () => {
            gsap.set(this.DOM.el, {zIndex: 1});
        },
        onComplete: () => {
            gsap.set(this.DOM.reveal, {opacity: 0});
        }
    })
    .to(this.DOM.revealInner, 0.2, {
        ease: 'Sine.easeOut',
        x: direction.x < 0 ? '100%' : '-100%'
    })
    .to(this.DOM.revealImage, 0.2, {
        ease: 'Sine.easeOut',
        x: direction.x < 0 ? '-100%' : '100%'
    }, 0);
}

Now we just need to update the animatableProperties object properties so the image can move around, rotate and change its brightness smoothly. We do this inside a requestAnimationFrame loop. In every cycle we interpolate the previous and current values so things happen with an easing.

We want to rotate the image and change its brightness depending on the x-axis speed (or distance traveled from the previous cycle) of the mouse. Therefore we need to calculate that distance for every cycle which we can get by subtracting the mouse position from the cached mouse position.

We also want to know in which direction we move the mouse since the rotation will be dependent on it. When moving to the left the image rotates negatively, and when moving to the right, positively.

Next, we want to update the animatableProperties values. For the translationX and translationY, we want the center of the image to be positioned where the mouse is. Note that the original position of the image element is on the left side of the menu item.

The rotation can go from -60 to 60 degrees depending on the speed/distance of the mouse and its direction. Finally the brightness can go from 1 to 4, also depending on the speed/distance of the mouse.

In the end, we take these values together with the previous cycle values and use interpolation to set up a final value that will then give us that smooth feeling when animating the element.

This is how the render function looks like:

render() {
    this.requestId = undefined;
    
    if ( this.firstRAFCycle ) {
        this.calcBounds();
    }

    const mouseDistanceX = clamp(Math.abs(mousePosCache.x - mousepos.x), 0, 100);
    direction = {x: mousePosCache.x-mousepos.x, y: mousePosCache.y-mousepos.y};
    mousePosCache = {x: mousepos.x, y: mousepos.y};

    this.animatableProperties.tx.current = Math.abs(mousepos.x - this.bounds.el.left) - this.bounds.reveal.width/2;
    this.animatableProperties.ty.current = Math.abs(mousepos.y - this.bounds.el.top) - this.bounds.reveal.height/2;
    this.animatableProperties.rotation.current = this.firstRAFCycle ? 0 : map(mouseDistanceX,0,100,0,direction.x < 0 ? 60 : -60);
    this.animatableProperties.brightness.current = this.firstRAFCycle ? 1 : map(mouseDistanceX,0,100,1,4);

    this.animatableProperties.tx.previous = this.firstRAFCycle ? this.animatableProperties.tx.current : lerp(this.animatableProperties.tx.previous, this.animatableProperties.tx.current, this.animatableProperties.tx.amt);
    this.animatableProperties.ty.previous = this.firstRAFCycle ? this.animatableProperties.ty.current : lerp(this.animatableProperties.ty.previous, this.animatableProperties.ty.current, this.animatableProperties.ty.amt);
    this.animatableProperties.rotation.previous = this.firstRAFCycle ? this.animatableProperties.rotation.current : lerp(this.animatableProperties.rotation.previous, this.animatableProperties.rotation.current, this.animatableProperties.rotation.amt);
    this.animatableProperties.brightness.previous = this.firstRAFCycle ? this.animatableProperties.brightness.current : lerp(this.animatableProperties.brightness.previous, this.animatableProperties.brightness.current, this.animatableProperties.brightness.amt);
    
    gsap.set(this.DOM.reveal, {
        x: this.animatableProperties.tx.previous,
        y: this.animatableProperties.ty.previous,
        rotation: this.animatableProperties.rotation.previous,
        filter: `brightness(${this.animatableProperties.brightness.previous})`
    });

    this.firstRAFCycle = false;
    this.loopRender();
}

I hope this has been not too difficult to follow and that you have gained some insight into constructing this fancy effect.

Please let me know if you have any question @codrops or @crnacura.

Thank you for reading!

The images used in the demo are by Andrey Yakovlev and Lili Aleeva. All images used are licensed under CC BY-NC-ND 4.0

The post Creating a Menu Image Animation on Hover appeared first on Codrops.


Source: codrops

Categories
Freelance Freelancers Invoicing and Accounting

How to Invoice Your Clients Professionally (10 Tips)

Let’s face it – while receiving money can be very addictive, invoicing is a total nightmare for freelancers, especially designers. However, the freelance business’s truth is that…

Visit hongkiat.com for full content.
Source: hongkiat

Categories
Uncategorized

Information And Information Architecture: The BIG Picture

Information And Information Architecture: The BIG Picture

Information And Information Architecture: The BIG Picture

Carrie Webster

2020-07-01T12:30:00+00:00
2020-07-05T00:11:03+00:00

We are living in a world exploding with information, but how do we find what is relevant to us at the time that we need it? I believe that good information architecture is key to helping us navigate through the mountains of data and information we have created for ourselves. 

In this article, we will first describe what information architecture is, why it’s important, and approaches to effective implementation. Then we explore ideas around the broader view of the information age, how we use information, and how it impacts our world and our lives. These insights are designed to help you to understand the bigger picture, which enables us to grasp the value that good information architecture delivers to help our information-overloaded lives.

What Is Information Architecture And Why Is It Important?

“Information architecture is the practice of deciding how to arrange the parts of something to be understandable.”

The Information Architecture Institute

From a user experience perspective, this really means understanding how your users think, what problems they are trying to solve, and then presenting information in a logical way that makes sense from within this context. 

Whether it is a website, a software application or a smartphone app, it’s about first designing the structure of how your information is organized, and then translating this into a logical navigation hierarchy that makes sense to the users who will be accessing it. In this world where we can sometimes feel as though we are drowning in data, information architecture provides us with a logical way of organizing this data to make it easier to locate. 

Here are some other reasons why good information architecture is important:

For The User

  • It reduces cognitive load.
    Too much information on a screen with no clear pathway can make it difficult for a user to focus. Too many options can lead to choice deferral where a user chooses not to make a decision at all.
  • It speeds up the process of finding the right information.
    This is the opposite of choice deferral, where the user is able to easily locate what they are looking for with clear navigation choices.
  • It can keep the user focussed on the task they are trying to achieve.
    If the task a user is engaging in is easy to follow without additional non-contextual navigation elements, it’s less likely they will be distracted.
  • It makes it easier to analyze and understand information by the addition of context.
    Providing a visual navigation path of exactly where the user is within a website can provide more context for the content they are viewing. For example, during an online bank account application, displaying the total number of steps in the process and visually indicating exactly which step you are at, and what the next steps may involve gives context to the flow.
  • Reduces frustration and contacting support.
    If it is clear to the user where they can find what they need, there is no need to request help. For example, if a customer has received a purchased item that is faulty, without obvious instruction on how to rectify the situation, they may call the customer support center. 

Below are a couple of examples helping to illustrate the points about the user.

Wizard example

(Image source: Shaun Utter) (Large preview)

The example above demonstrates:

  • The use of a “wizard” style application form and illustrates many of the points above. 
  • Clear navigation steps across the top of the page providing context as to where the user is in the process.
  • Simple choices to guide the user. 
  • Contextual information links in the form of FAQs relating to the step the user is at. 
  • Navigation button at the bottom of the page giving specific instructions for the next step.

(Large preview)

The website example above, Punk Avenue shows another example of clear main navigation, with a brief summary of what you will find on each page. Below that is a series of tabs that keep you on the same page and visually indicate what information you are viewing. 

For A Business

  • Keeps customers on their website for longer.
    Research shows that visitors to a website will often leave within 10-20 seconds, but with a clear purpose, you can engage your visitors for a longer period. Although good design and messaging help to present the site’s value proposition, a well-designed navigation display can also contribute to demonstrate what kind of information supports this value proposition.

  • Increases the chance of customer conversion.
    If your site visitor can find what they want via the navigation, and there are simple and minimal steps provided on how to acquire it, the chances of conversion are far higher than a site design that is unable to direct the user to the right information.

  • Reduces risk of customers going to a competitor.
    If a visitor to your site can easily find what they are looking for through effective navigation and good design, chances are they’ll stay there rather than move onto the next Google search result.

  • Reduces duplication of information (by design).
    Good information architecture can ensure that the same or similar content is not replicated. Understanding and documenting the content structure, particularly on information-heavy sites, can prevent these potential issues.

  • Better ROI through efficient use of the platform.
    The investment spent on ensuring that the information architecture on your site is effective and makes sense to your users is a compelling way to increase your customer conversions and the income derived from those sales.

  • Reduces cost of support when a user can’t find something.
    As described earlier, creating an unnecessary load on the customer support team is an additional cost that can be avoided by a site that functions well and provides assistance for customers when they need it. 

The example below helps to illustrate some of the points above about business.

(Image source: Optimizely Blog) (Large preview)

The example above demonstrates how poor navigation displays can impact customer conversion. This case study shows an increase in customer revenue by 53.8%. The additional information in-between the search bar and the products was removed which also served to move the product display closer to the top of the page. The vertical information that was removed created the effect of what may have been perceived as a superfluous navigation bar, or maybe just information that was not considered relevant for a user in their product search. 

When thinking about designing the information architecture for your website or app, efficient site navigation is crucial.


As a designer, ask yourself “Does the language resonate with the user, does the hierarchy make sense to the user flow, can they easily find their way back to where they were?”

If your website is content-heavy, you may also consider the use of site search. Let’s explore some research around site search vs navigation.

Search vs Navigation

In 1997, Jakob Neilson conducted a study that showed over 50% of website users would use the search function over site navigation. In 2012, econsultancy.com reported that 30% of website visitors to e-commerce sites will use the site search, while a Kiss metrics study found that 40% of users preferred using search. In 2010, Gerry Mcgovern’s study demonstrated 30% of users preferring search.

(Image source: Neil Patel) (Large preview)

Although the relationship between these findings may seem elusive, one thing is clear; and that is that users will use both site search and site navigation to find information, in varying proportions.

In order to provide the best user experience for your customers, you may need to consider integrating a site search, in conjunction with an effective and well-designed site navigation if your website has a complex structure and large amounts of information.

Here is a practical example of where a site search would be useful for site visitors. Let’s say you visit a website that sells cleaning and health products, and you were looking to buy some antibacterial hand wash. There are two categories you can see, “Body Washing Products” and “Skin Cleansers”. Which one do you choose? 

Body washing products

Body washing products (Image source: Good Housekeeping) (Large preview)

Skin cleansers

Skin cleansers (Image source: Skincare Hero) (Large preview)

And if you were to browse these categories that may have products listed alphabetically, there may be a large list to scan through. Below are some similar phrases that could be used, depending on what any individual’s idea of antibacterial hand wash could also be called:

  • hand sanitizer
  • sanitizing soap
  • hand disinfectant
  • disinfectant hand wash
  • hand sterilizer
  • hygienic soap
  • antiseptic handwash

If you are looking for “hygienic soap”, it may take you a while to scan the list to find the “antibacterial hand wash”. As it is difficult to cater to all possible synonym variations in the navigation structure of a site, a well-designed site search can allow users to search for these variations, by adding what we call metatags to each piece of content. For example, the “antibacterial hand wash” product could have additional hidden information or tags that include all the terms listed above, allowing users to search for any of these and return search results that match.

The Politico website below uses both navigation and a search function. It demonstrates an example of a content-heavy site that groups the information into categories making it easier to find topics. The site utilizes a “megamenu” which is accessed from the top left corner of the page. This is a common way to provide a menu of options with categories and subcategories that can be used for those visitors that want to browse content, and the search function can be used to locate a specific piece of information.

(Large preview)

According to research from measuringu.com, about 14% of users will start with a search and the rest will start by browsing through the navigation options.

Good And Bad Information Architecture Examples

Let’s review some website examples demonstrating good and bad uses of information architecture. Great navigation is a reflection of well-designed information architecture that considers the target audience’s needs.

Useful Navigation

This Sears website makes good use of mega drop-down menus. These help to provide navigation options to sub-categories that are clearly grouped. It also uses images to provide much faster cognition for the user.

(Large preview)

Pinterest demonstrates a useful way to present visual user-generated content based on search terms. The search is the navigation. This works well based on the sheer amount of content available on the site, which would make it difficult to provide a simple navigation system based on categories.

Pinterest website

Pinterest (Large preview)

Overwhelming Navigation

This website example is complete information overload with bad use of white space and way too many choices. It doesn’t help that the design of the website is cramped making it hard to identify all the options available.  

Frys.com

(Large preview)

How Do You Get It Right?

Here is a brief list of considerations and processes to use when you are designing the information architecture for a product or service.

  • First understand your user’s needs and what tasks they are trying to achieve.
    You can conduct user interviews to really understand what problems your product or service is solving. From here, think about how they might interact with your website and what pathways they could take to achieve their objectives.
  • Try to create a hierarchy with minimal sub-levels.
    If you can achieve this, then the user can access any information on your site with a maximum of two clicks.

Sitemap example

Map out your site navigation to see if you can organise into a minimal number of sub-levels or categories. (Large preview)
  • Don’t use jargon in the navigation language.
    Understand the language of your audience. Test with your users to ensure they understand the correct meaning of the language used.
  • Don’t rely on images or icons alone as a navigation tool.
    There are very few universally understood icons, such as Help, Error, and Print, and these may differ culturally. 

(Large preview)

iphone icons with labels

Note that on smartphones, icons are always accompanied by a text label to help you navigate. (Large preview)
  • Always indicate to the user exactly where they are within the site so they can easily navigate back to a previous page. Breadcrumb navigation is one example of how to do this effectively as shown in the example below. It can sit below the main navigation showing you each page you have clicked on with the current location displaying as the last on the right.

Breadcrumb examples

Breadcrumb navigation example (Large preview)
  • Use design to create distinct visual differences between the hierarchy levels.
    For example, a top-level hierarchy heading may be displayed with a larger font size. These visual differences can guide the user’s eye to more important information first. It can also be the job of the visual designer to help differentiate these areas.

Methods To Test Your Navigation

Card Sorting

Write out the name of each information section on paper, and have participants sort cards containing all your navigation sections into groups that make sense to them. Try doing this same sort with at least five participants so you can start to identify patterns and preferences for the categories and subcategories that are created. This is called an open card sort. A closed card sort can be used if you decide to have predetermined top-level categories that the participants place the cards under based on what makes sense to them.

Card sorting

Card sorting (Image source: UX Indonesia on Unsplash) (Large preview)

Recommended reading: Card Sorting Beginner’s Guide: Improving Your Information Architecture

Scenario Testing

By using a wireframe or prototype, ask participants to complete a specific task by navigating through the site. You can use a clickable wireframe to test this by observing how clear it is for a user to carry out the activity. An example task (refer to the wireframe below) might be to register on the website and then make a booking for a single event and publish it.

Wireframe example

Scenario testing (Large preview)

Tools

Treejack is a tool that allows you to validate your navigation structure. It asks the participants to indicate where they would look to find specific information and provides you with insightful actions.

Treejack tool

Navigation testing tool (Large preview)

Free Keyword Tools

You can use free tools to help to identify commonly used search terms that can help with language choice in your navigation. For example, answerthepublic.com is a free site that allows you to enter a search term to see what other related search terms are being used.

Answer the public keyword search tool

Keyword search tool (Large preview)

We’ve covered the basics of information architecture, and now it’s time to move onto the bigger picture, the Information Age. Understanding context around the massive amounts of data and information we are surrounded by can help to shape your outlook as a UX designer, as it has helped inform the direction and approach to my own design practice.

The Information Age

We live in a time where our access to information is unprecedented. It is instantaneous, it is global, it is everywhere, it is the Internet. News stories are broadcast as they unfold, communication with friends and family in other parts of the world has never been easier, and Google has become our personal library of virtually limitless topics. Information is king and queen. 

Key Facts About Information

  • 90% of the world’s data has been created in the past 2 years.
  • The amount of data in the world doubles every two years.
  • If all the data in our world was stored on 128G iPad tablets, they would create a stack going from the Earth to the Moon 6.6 times! 
  • Only 37% of all data is considered “useful”. And of that 37%, a much smaller percentage is actually analyzed.
  • 33 percent of managers feel that information overload was impacting their health.
  • 66 percent of managers reported increased conflict with teammates as well as reduced job satisfaction.

And finally, let’s examine how information can be used and abused in this age of information.


“We live in a time where our access to information is unprecedented. It is instantaneous, it is global, it is everywhere, it is the Internet.”

The Power Of Information

“With power comes great responsibility.”

This famous quote is often attributed to Uncle Ben from Spiderman. We can think of this in reference to how powerful information can be, but when in the wrong hands, there is an opportunity to abuse this power. Below is my perspective on how the power of information can manifest in our world, and why it is both a precious and dangerous commodity. 

“Information Is Power”

Internet activist, Aaron Swartz, took his life in 2013 at the age of 26. Aaron was the original creator of Reddit, and among many achievements, his untimely death occurred when he was fighting felony charges for illegally accessing and downloading academic information. He wrote a manifesto that called for activists to “liberate” information secured by corporations, and campaigned against Internet censorship. 

We recognize that information alone is useless if no one can find it. And then once it is made available, it needs to be acted upon. On a large scale, information can be shared to protect public health and safety, to help governments to create better policies and to empower individuals to live better lives. It can also be used for propaganda purposes for political gain, to create fear for the purpose of control, and to instill beliefs for the sole purpose of financial profit. 

Information Can Change World Events In An Instant

How quickly have governments pivoted and changed their approach to the COVID-19 pandemic based on new information? Not to mention the release of conflicting information from alternate sources that has also created mass confusion.

An example of this pivot was seen in Australia, when our Prime Minister announced non-elective surgery would be suspended from March 26, but just hours later, it was moved to April 1st after the health minister met with the private hospital sector that afternoon. This was due to the updated information received that would see the stand-down of medical staff, even as hospitals prepared for a surge in COVID-19 cases. 

Dangers Of Misinformation

In current times, examples: “Fake news” claims, presidential tweets, and allegations of misinformation coming from China around the COVID19 pandemic. Donald Trump who is attributed with the reference to “Fake News”, now more generally attributes incorrect news reporting to journalists and media outlets such as CNN.

Unfounded “conspiracy theories” are another example of ways to link seemingly related information points that have no solid relationship evidence. For example:

Information Security

In 2018, it was revealed Facebook was exposed to a massive security breach after hackers exploited a vulnerability to access user’s personal data. The impact of the access to this kind of personal information could have ramifications for those individuals impacted for years to come.

In July 2017, shortly after I left employment at Equifax (no connection whatsoever!), a data breach impacting over 147 million people occurred in the US. The data exposed included Social Security numbers, birth dates, and some credit card details. After spending $1.4 billion on security upgrades, it is still resolving ongoing class actions from consumers that were impacted.

The importance of protecting privacy and personal data has become increasingly important throughout the world. 132 of 194 countries currently have legislation in place to protect the sharing of personal information without consent, and the data and privacy of individuals. In 2017-18 there was a 10% rise in the number of countries enacting data privacy laws.

Based on the examples above, it is clear that information in itself doesn’t discriminate for good or for evil. That’s why it is so important to validate data sources and analyze information before taking it on board.

Conclusion

We have reviewed how we use information, the power it yields, the sheer volume of data we have created, the impacts of information overload, and how information architecture can be used to organize and structure this information for those seeking it. There is no denying that in this age of Information why it is so important to focus on information architecture as a solid foundation for delivering the right information to your customers to make their lives easier.

Further Reading on SmashingMag:

Smashing Editorial
(ah, ra, il)

Source: smash mag

Categories
design handoff design workflow designer to developer Interactive Design what developers need what to send developers

Show Them Your Assets – Tips for Handing Off Designs to Developers

You’ve been working away at your latest design project, and the client has given the go-ahead on your lovingly created digital concepts. Now it’s time to bring those designs to life, and you have a developer queued up to do just that.

So your part’s done, right? Not quite. You’re going to want to make sure your developer has the best head start they can in order to create the site as you imagined.

Below are a few tips to make that handover process a little easier.

Communicate to Make It Great

Get Talking

Scheduling a face-to-face meeting with your developer to talk over your project’s specifics and ambitions will help align your expectations and make the intent behind your concepts more clear. It’s quite likely they’ll even ask questions and request assets you haven’t even thought of yet!

It’s not just a one-and-done thing either, your developer’s going to have questions or requirements that arise as the project progresses. Deciding on a communication channel to allow easy discussion will help you both immensely.

Annotating Your Concepts

Developers might seem like magicians with the way they bring your websites to life, but they’re not clairvoyant! Annotating your concepts where advanced functionality is required reduces ambiguity and makes it more likely that your cool, quirky idea is going to make it to production. If it’s a feature that’s particularly unusual, you might want to find an example of a website or code sandbox that does something similar.

An example of Figma’s comment tool in use to make developer notes.

Figma and Sketch both have comment functionality in order to make annotations a little easier, also allowing multiple parties to comment. If dealing with PDFs, there is also an annotation tool available through Adobe Acrobat.

Specify the Basics

The basis of modern front end development revolves around DRY thinking. Some might argue thinking about code can be pretty dry, but we’re not talking about that – in this case, DRY stands for Don’t Repeat Yourself.  Most developers will tackle a project by starting with defining variables: what colors, font sizes, grid columns… anything that can be reused! Good, consistent design follows this same principle – although it’s a habit that can be hard to get going at first.

Tip: It’s always easier to define variables if this mentality is approached towards the start of the project!  

Colors

Make a style guide that specifies the colors you’ve used in your designs. Think about their logical applications to help signpost how they might work as a variable – for example, what colors did you use for paragraph text, hyperlinks and backgrounds? Did you consider colors to convey status messaging, such as successes, warnings and errors?

Typefaces

Which fonts have you used for your project? Is there a consistent set of font sizes you used throughout? If you haven’t already, maybe consider a ratio-based type scale – I like to use ModularScale to help with this.

Basic HTML Elements

Think about general styling for these basic html tags:

  • Paragraphs <p>
  • Headings <h1–h6>
  • Bullet lists <ul> and numbered lists <ol>
  • Emphasized text <b>, <strong> and <em>

Buttons

How about buttons and links? What should they do when they’re hovered over, focused (using the tab key on a keyboard) or disabled?

Forms Fields and Inputs

What should form fields look like? Is there any validation checking that should occur when a form is submitted?  How about checkboxes and radio buttons?

It’s unlikely that you’re going to be able to cover absolutely every single eventuality – allow your developer to use some common sense to fill in the gaps, and be available to them if they have any questions. In the words of John Maxwell and your aunt’s home office wall sticker, teamwork makes the dream work.

Get Your Favic-on

Favicons are widely recognized as the small icon that appears to the left of the site title on your browser’s tab bar. Nowadays, the application of your site’s favicon is much further reaching, showing up in Google search results and app tiles. There’s also extra theming options available, such as the ability to customize the color of Google Chrome Android’s browser bar color for your site.

Using a generator site such as realfavicongenerator takes the pain out of much of this decision-making, allowing you to upload specific graphics as desired, creating silhouettes of your icon for Windows Metro tiles and macOS Safari pins, and packaging everything into easy-to-use files and code.

 Compress Your Images

Nobody wants to load a 20MB image when they’re on a slow connection or a data plan – it pays dividends to plan ahead and downsize your images so that they’re production-ready for the web. If you’re worried image compression is going to harm your image quality, fear not – you can go a long way with image compression before quality is seriously compromised.

  1. Start by reducing the image resolution – for batch jobs, I use Adobe Photoshop’s image processor script to downsize images to fit 1920 x 1200 pixels
  2. Alternatively, if you’re working on a static project – where specific images will be used only in specific places – you could use your design software (nearly all mainstream UI software allows you to do this now) to export your images at 2x size to support devices with high pixel densities.
  3. I also convert my image color profiles to SRGB to ensure consistency across most modern display types (this one’s optional)
  4. I then take my newly downsized images and run them through imageOptim at 80% quality. Generally I would aim to get my images under 300kb – if there are any that are still significantly over this target once compressed, I’d run these through again at 70% quality (I wouldn’t recommend going lower than this, though).

Don’t forget you can also do this for PNGs! Enabling PNGCrush in imageOptim will let you significantly reduce the size of PNGs… just be ready for it to take a while.

Make Your Vectors SVG-Easy to Use

If your design contains graphics or illustrations you created using vector software, it can be used on the web as an SVG file. Usually, these files will be a lot smaller than JPGs or PNGs. You can export graphics in most (if not all) vector software in this format.

Optionally, you could use imageOptim or SVGOMG to compress the SVG code without sacrificing quality. Your developer might already use a script that does this automatically when processing the site for production, so it may be worth asking ahead.

Get Your Licenses in Check

If you’re using premium fonts, make sure you’ve purchased a webfont license so you can hand over the correct files to the developer. I’d recommend doing this sooner rather than later – although not often, occasionally web versions of fonts can have slightly different bounding boxes to their desktop counterparts, making it a real pain for developers to work with further down the line.

If you’ve been using samples of stock photos (or if you’ve been going crazy lifting whatever you can find on Google Images), make sure everything is kosher before you go live. Make sure you purchase licensed photos, and if certain photos you want to use require attribution, make the developer aware of this.

Source

p img {display:inline-block; margin-right:10px;}
.alignleft {float:left;}
p.showcase {clear:both;}
body#browserfriendly p, body#podcast p, div#emailbody p{margin:0;}

Source: Web Designer Depot

Categories
Gadgets Gift Guides

Five Best Smart Watches You Can Buy

When it comes to smart wearables, smartwatches win the game in terms of usability and aesthetics. It’s easy to carry a smartwatch on you all the time and the many features make your life easy….

Visit hongkiat.com for full content.
Source: hongkiat