About

Saturday, October 30, 2021

Some Articles About Accessibility I’ve Saved Recently IV


The post Some Articles About Accessibility I’ve Saved Recently IV appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/some-articles-about-accessibility-ive-saved-recently-iv/

Friday, October 29, 2021

Functional Dependencies in SQL GROUP BY

The SQL standard knows an interesting feature where you can project any functional dependencies of a primary (or unique) key that is listed in the GROUP BY clause without having to add that functional dependency to the GROUP BY clause explicitly.

What does this mean? Consider this simple schema:

CREATE TABLE author (
  id INT NOT NULL PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE book (
  id INT NOT NULL PRIMARY KEY,
  author_id INT NOT NULL REFERENCES author,
  title TEXT NOT NULL
);

In order to count the number of books by author, we tend to write:

SELECT a.name, count(b.id)
FROM author a
LEFT JOIN book b ON a.id = b.author_id
GROUP BY 
  a.id,  -- Required, because names aren't unique
  a.name -- Required in some dialects, but not in others

We have to group by something unique in this case, because if two authors are called John Doe, we still want them to produce separate groups. So GROUP BY a.id is a given.

We’re used to also GROUP BY a.name, especially in these dialects that require this, since we list a.name in the SELECT clause:

  • Db2
  • Derby
  • Exasol
  • Firebird
  • HANA
  • Informix
  • Oracle
  • SQL Server

But is it really required? It isn’t as per the SQL standard, because there is a functional dependency between author.id and author.name. In other words, for each value of

But is it really required? It isn’t as per the SQL standard, because there is a functional dependency between author.id and author.name. In other words, for each value of author.id, there is exactly one possible value of author.name, or author.name is a function of author.id

This means that it does not matter if we GROUP BY both columns, or only the primary key. The result must be the same in both cases, hence this is possible:

SELECT a.name, count(b.id)
FROM author a
LEFT JOIN book b ON a.id = b.author_id
GROUP BY a.id

Which SQL dialects support this?

At least the following SQL dialects support this language feature:

  • CockroachDB
  • H2
  • HSQLDB
  • MariaDB
  • MySQL
  • PostgreSQL
  • SQLite
  • Yugabyte

It’s noteworthy that MySQL used to simply ignore whether a column could be projected unambiguously or not, in the presence of GROUP BY. While the following query was rejected in most dialects, it was not, in MySQL, prior to the introduction of the ONLY_FULL_GROUP_BY mode:

SELECT author_id, title, count(*)
FROM author
GROUP BY author_id

What should we display for author.title, if an author has written more than one book? It doesn’t make sense, yet MySQL still used to allow it, and would just project any arbitrary value from the group.

Today, MySQL only allows for projecting columns with a functional dependency on the GROUP BY clause, as is permitted by the SQL standard.

Pros & Cons

While the shorter syntax that avoids the extra columns might be easier to maintain (easy to project additional columns, if required), there is some risk of queries breaking in production, namely when underlying constraints are disabled, e.g. for a migration. While it is unlikely that a primary key is disabled in a live system, it could still be the case, and without the key, a previously valid query will no longer be valid for the same reason why MySQL’s old interpretation was invalid: There’s no longer a guarantee of functional dependency.

Other syntax

Starting from jOOQ 3.16, and #11834, it will be possible to reference tables directly in the GROUP BY clause, instead of individual columns. For example:

SELECT a.name, count(b.id)
FROM author a
LEFT JOIN book b ON a.id = b.author_id
GROUP BY a

The semantics will be:

  • If the table has a primary key (composite or not), use that in the GROUP BY clause, instead
  • If the table doesn’t have a primary key, list all the columns from the table instead.

Since none of the RDBMS supported by jOOQ currently supports this syntax, it is a purely synthetic jOOQ feature.



from Java, SQL and jOOQ. https://ift.tt/2Zv6X4A
via IFTTT

Okhsv and Okhsl

There is an old Russian fable where Okhsv and Okhsl are on a rowboat and Okhsv says to Okhsl, “What are the known shortcomings of HSL and HSV color pickers in design applications?” I kid, I kid. But really, what are they?

Björn Ottosson shows the two classics:

Despite color picking playing a big role in a lot of applications, the design of color pickers isn’t a particularly well researched topic. While some variation exist in the widgets themselves, the choice of HSL or HSV is mostly taken for granted, with only a few exceptions.

Is their dominance well deserved or would it be possible to create better alternatives?

It’s all rather above my head, but I certainly support the idea of researching and exploring things that so many of us just take for granted. There is a whole playground comparing different possibilities. It’s not so much about the UI/UX of the picker itself, but how the range of colors is expressed in the picker area.

Direct Link to ArticlePermalink


The post Okhsv and Okhsl appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://bottosson.github.io/posts/colorpicker/

Vite + _____

Vite, “Next Generation Frontend Tooling” from Evan You, has been capturing a lot of attention. I’ve heard rave reviews from developers, even in private chats (you gotta try this!). Being from Evan, Vite works great with Vue, but Vue doesn’t seem to be the only first-class citizen of Vite. The plugins support Vue and React just the same and it looks like configurations for lit, Preact, and Svelte are easy.

It’s interesting to see other technologies try to get on the bandwagon, almost certainly for the wicked speed. I believe it uses esbuild, which is known for speed, for… some things?… under the hood, but not bundling. Just noting some of this bandwagon stuff happening like…

Hey, people like speed and good DX. Always worth noting when you see this much movement.


The post Vite + _____ appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/vite-plus-blank/

Thursday, October 28, 2021

Merge Conflicts: What They Are and How to Deal with Them​

This article is part of our “Advanced Git” series. Be sure to follow Tower on Twitter or sign up for their newsletter to hear about the next articles.

Merge conflicts… Nobody likes them. Some of us even fear them. But they are a fact of life when you’re working with Git, especially when you’re teaming up with other developers. In most cases, merge conflicts aren’t as scary as you might think. In this fourth part of our “Advanced Git” series we’ll talk about when they can happen, what they actually are, and how to solve them.

Advanced Git series:

  1. Part 1: Creating the Perfect Commit in Git
  2. Part 2: Branching Strategies in Git
  3. Part 3: Better Collaboration With Pull Requests
  4. Part 4: Merge Conflicts (You are here!)
  5. Part 5: Rebase vs. Merge (Coming soon!)
  6. Part 6: Interactive Rebase
  7. Part 7: Cherry-Picking Commits in Git
  8. Part 8: Using the Reflog to Restore Lost Commits

How and when merge conflicts occur

The name gives it away: a merge conflict can occur when you integrate (or “merge”) changes from a different source into your current working branch. Keep in mind that integration is not limited to just merging branches. Conflicts can also happen during a rebase or an interactive rebase, when you’re cherry picking in Git (i.e. when you choose a commit from one branch and apply it to another), when you’re running git pull or even when reapplying a stash.

All of these actions perform some kind of integration, and that’s when merge conflicts can happen. Of course, this doesn’t mean that every one of those actions results in a merge conflict every time — thank goodness! But when exactly do conflicts occur?

Actually, Git’s merging capabilities are one of its greatest advantages: merging branches works flawlessly most of the time because Git is usually able to figure things out on its own and knows how to integrate changes.

But there are situations where contradictory changes are made — and that’s when technology simply cannot decide what’s right or wrong. These situations require a decision from a human being. For example, when the exact same line of code was changed in two commits, on two different branches, Git has no way of knowing which change you prefer. Another situation that is a bit less common: a file is modified in one branch and deleted in another one. Git will ask you what to do instead of just guessing what works best.

How to know when a merge conflict has occurred

So, how do you know a merge conflict has occurred? Don’t worry about that — Git will tell you and it will also make suggestions on how to resolve the problem. It will let you know immediately if a merge or rebase fails. For example, if you have committed changes that are in conflict with someone else’s changes, Git informs you about the problem in the terminal and tells you that the automatic merge failed:

$ git merge develop
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

You can see that I ran into a conflict here and that Git tells me about the problem right away. Even if I had missed that message, I am reminded about the conflict the next time I type git status.

If you’re working with a Git desktop GUI like Tower, the app makes sure you don’t overlook any conflicts:

In any case: don’t worry about not noticing merge conflicts!

How to undo a merge conflict and start over

You can’t ignore a merge conflict — instead, you have to deal with it before you can continue your work. You basically have the following two options:

  • Resolve the conflict(s)
  • Abort or undo the action that caused the conflict(s)

Before we go into resolving conflicts, let’s briefly talk about how to undo and start over (it’s very reassuring to know this is possible). In many cases, this is as simple as using the --abort parameter, e.g. in commands like git merge --abort and git rebase --abort. This will undo the merge/rebase and bring back the state before the conflict occurred.

This also works when you’ve already started resolving the conflicted files and, even then, when you find yourself at a dead end, you can still undo the merge. This should give you the confidence that you really can’t mess up. You can always abort, return to a clean state, and start over.

What merge conflicts really look like in Git

Let’s see what a conflict really looks like under the hood. It’s time to demystify those little buggers and get to know them better. Once you understand a merge conflict, you can stop worrying.

As an example, let’s look at the contents of an index.html file that currently has a conflict:

Screenshot of an open code editor with HTML markup for a navigation that contains an unordered list of links. There are three lines of text injected by Git, the first says HEAD, the second is a line of equals signs, and the last says develop.

Git is kind enough to mark the problematic areas in the file. They’re surrounded by <<<<<<< and >>>>>>>. The content after the first marker originates from our current working branch (HEAD). The line with seven equals signs (=======) separates the two conflicting changes. Finally, the changes from the other branch are displayed (develop in our example).

Your job is to clean up those lines and solve the conflict: in a text editor, in your preferred IDE, in a Git desktop GUI, or in a Diff & Merge Tool.

How to solve a conflict in Git

It doesn’t matter which tool or application you use to resolve a merge conflict — when you’re done, the file has to look exactly as you want it to look. If it’s just you, you can easily decide to get rid of a code change. But if the conflicting change comes from someone else, you might have to talk to them before you decide which code to keep. Maybe it’s yours, maybe it’s someone else’s, and maybe it’s a combination of those two.

The process of cleaning up the file and making sure it contains what you actually want doesn’t have to involve any magic. You can do this simply by opening your text editor or IDE and making your changes.

Sometimes, though, you’ll find that this is not the most efficient way. That’s when dedicated tools can save time and effort. For example, there are various Git desktop GUIs which can be helpful when you’re resolving merge conflicts.

Let’s take Tower as an example. It offers a dedicated “Conflict Wizard” that makes these otherwise abstract situations more visual. This helps to better understand where the changes are coming from, what type of modification occurred, and ultimately solve the situation:

Especially for more complicated conflicts, it can be great to have a dedicated Diff & Merge Tool at hand. It can help you understand diffs even better by offering advanced features like special formatting and different presentation modes (e.g. side-by-side, combined in a single column, etc.).

There are several Diff & Merge Tools on the market (here are some for Mac and for Windows). You can configure your tool of choice using the git config command. (Consult the tool’s documentation for detailed instructions.) In case of a conflict, you can invoke it by simply typing git mergetool. As an example, I’m using the Kaleidoscope app on my Mac:

After cleaning up the file — either manually in a text editor, in a Git desktop GUI, or with a Merge Tool — you can commit the file like any other change. By typing git add <filename>, you inform Git that the conflict has been resolved.

When all merge conflicts have been solved and added to the Staging Area, you simply create a regular commit. And this completes the conflict resolution.

Don’t panic!

As you can see, a merge conflict is nothing to worry about and certainly no reason to panic. Once you understand what actually happened to cause the conflict, you can decide to undo the changes or resolve the conflict. Remember that you can’t break things — even if you realize you made a mistake while resolving a conflict, you can still undo it: just roll back to the commit before the great catastrophe and start over again.

If you want to dive deeper into advanced Git tools, feel free to check out my (free!) “Advanced Git Kit”: it’s a collection of short videos about topics like branching strategies, Interactive Rebase, Reflog, Submodules and much more.

Advanced Git series:

  1. Part 1: Creating the Perfect Commit in Git
  2. Part 2: Branching Strategies in Git
  3. Part 3: Better Collaboration With Pull Requests
  4. Part 4: Merge Conflicts (You are here!)
  5. Part 5: Rebase vs. Merge (Coming soon!)
  6. Part 6: Interactive Rebase
  7. Part 7: Cherry-Picking Commits in Git
  8. Part 8: Using the Reflog to Restore Lost Commits

The post Merge Conflicts: What They Are and How to Deal with Them​ appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/merge-conflicts-what-they-are-and-how-to-deal-with-them/

Building an Angular Data Grid With Filtering

(This is a sponsored post.)

Kendo UI makes it possible to go from a basic idea to a full-fledged app, thanks to a massive component library. We’re talking well over 100 components that are ready for you to drop into your app at will, whether it’s React, Angular or Vue you’re working in — they just work. That is because Kendo UI is actually a bundle of four JavaScript libraries, each built natively for their respective framework. But more than that, as we’ve covered before, the components are super themeable to the extent that you can make them whatever you want.

But here’s the real kicker with Kendo UI: it takes care of the heavy lifting. The styling is great and all, but what separates Kendo UI from other component frameworks is the functionality it provides right out of the box.

Case in point: data. Rather than spending all your time figuring out the best way to bind data to a component, that’s just a given which ultimately allows you to focus more of your time on theming and getting the UI just right.

Perhaps the best way to see how trivial Kendo UI makes working with data is to see it in action, so…

Let’s look at the Angular Grid component

This is the Kendo UI for Angular Data Grid component. Lots of data in there, right? We’re looking at a list of employees that displays a name, image, and other bits of information about each person.

Like all of Kendo UI’s components, it’s not like there’s one data grid component that they square-pegged to work in multiple frameworks. This data grid was built from scratch and designed specifically to work for Angular, just as their KendoReact Grid component is designed specifically for React.

Now, normally, a simple <table> element might do the trick, right? But Kendo UI for Angular’s data grid is chockfull of extras that make it a much better user experience. Notice right off the bat that it provides interactive functionality around things like exporting the data to Excel or PDF. And there are a bunch of other non-trivial features that would otherwise take a vast majority of the time and effort to make the component.

Filtering

Here’s one for you: filtering a grid of data. Say you’re looking at a list of employees like the data grid example above, but for a company that employees thousands of folks. It’d be hard to find a specific person without considering a slew of features, like search, sortable columns, and pagination — all of which Kendo UI’s data grid does.

Users can quickly parse the data bound to the Angular data grid. Filtering can be done through a dedicated filter row, or through a filter menu that pops up when clicking on a filter icon in the header of a column. 

One way to filter the data is to click on a column header, select the Filter option, and set the criteria.

Kendo UI’s documentation is great. Here’s how fast we can get this up and running.

First, import the component

No tricks here — import the data grid as you would any other component:

import { Component, OnInit, ViewChild } from '@angular/core';
import { DataBindingDirective } from '@progress/kendo-angular-grid';
import { process } from '@progress/kendo-data-query';
import { employees } from './employees';
import { images } from './images';

Next, call the component

@Component({
  selector: 'my-app',
  template: `
    <kendo-grid>
      // ...
    </kendo-grid>
  `
})

This is incomplete, of course, because next we have to…

Configure the component

The key feature we want to enable is filtering, but Kendo’s Angular Grid takes all kinds of feature parameters that can be enabled in one fell swoop, from sorting and grouping, to pagination and virtualization, to name a few.

Filtering? It’s a one-liner to bind it to the column headers.

@Component({
  selector: 'my-app',
  template: `
    <kendo-grid
      [kendoGridBinding]="gridView"
      kendoGridSelectBy="id"
      [selectedKeys]="mySelection"
      [pageSize]="20"
      [pageable]="true"
      [sortable]="true"
      [groupable]="true"
      [reorderable]="true"
      [resizable]="true"
      [height]="500"
      [columnMenu]="{ filter: true }"
    >
      // etc.
    </kendo-grid>
  `
})

Then, mark up the rest of the UI

We won’t go deep here. Kendo UI’s documentation has an excellent example of how that looks. This is a good time to work on the styling as well, which is done in a styles parameter. Again, theming a Kendo UI component is a cinch.

So far, we have a nice-looking data grid before we even plug any actual data into it!

And, finally, bind the data

You may have noticed right away when we imported the component that we imported “employee” data in the process. We need to bind that data to the component. Now, this is where someone like me would go run off in a corner and cry, but Kendo UI makes it a little too easy for that to happen.

// Active the component on init
export class AppComponent implements OnInit {
  // Bind the employee data to the component
  @ViewChild(DataBindingDirective) dataBinding: DataBindingDirective;
  // Set the grid's data source to the employee data file
  public gridData: any[] = employees;
  // Apply the data source to the Grid component view
  public gridView: any[];

  public mySelection: string[] = [];

  public ngOnInit(): void {
    this.gridView = this.gridData;
  }
  // Start processing the data
  public onFilter(inputValue: string): void {
    this.gridView = process(this.gridData, {
      filter: {
        // Set the type of logic (and/or)
        logic: "or",
        // Defining filters and their operators
        filters: [
          {
            field: 'full_name',
            operator: 'contains',
            value: inputValue
          },
          {
            field: 'job_title',
            operator: 'contains',
            value: inputValue
          },
          {
            field: 'budget',
            operator: 'contains',
            value: inputValue
          },
          {
            field: 'phone',
            operator: 'contains',
            value: inputValue
          },
          {
            field: 'address',
            operator: 'contains',
            value: inputValue
          }
        ],
      }
    }).data;

    this.dataBinding.skip = 0;
  }

  // ...
}

Let’s see that demo again


That’s a heckuva lot of power with a minimal amount of effort. The Kendo UI APIs are extensive and turn even the most complex feature dead simple.

And we didn’t even get to all of the other wonderful goodies that we get with Kendo UI components. Take accessibility. Could you imagine all of the consideration that needs to go into making a component like this accessible? Like all of the other powerful features we get, Kendo UI tackles accessibility for us as well, taking on the heavy lifting that goes into making a keyboard-friendly UI that meets WCAG 2.0 Alice standards and is compliant with Section 508 and WAI-ARIA standards.


The post Building an Angular Data Grid With Filtering appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/building-an-angular-data-grid-with-filtering/

Sticky Definition Lists

I ran across this 30 seconds of code website the other day, and they have a CSS section which is really good! The first example snippet I looked at was this “floating section headers” example, reminding me yet again how satisfying definition lists can be.

With nice simple HTML like this:

<div class="floating-stack">
  <dl>
    <dt>A</dt>
    <dd>Algeria</dd>
    <dd>Angola</dd>

    <dt>B</dt>
    <dd>Benin</dd>
    <dd>Botswana</dd>
    <dd>Burkina Faso</dd>
    <dd>Burundi</dd>

    <dt>C</dt>
    <dd>Cabo Verde</dd>
    <dd>Cameroon</dd>
    <dd>Central African Republic</dd>
    <dd>Chad</dd>
    <dd>Comoros</dd>
    <dd>Congo, Democratic Republic of the</dd>
    <dd>Congo, Republic of the</dd>
    <dd>Cote d'Ivoire</dd>

    <dt>D</dt>
    <dd>Djibouti</dd>

    <dt>E</dt>
    <dd>Egypt</dd>
    <dd>Equatorial Guinea</dd>
    <dd>Eritrea</dd>
    <dd>Eswatini (formerly Swaziland)</dd>
    <dd>Ethiopia</dd>
  </dl>
</div>

The default browser styling — no CSS at all — looks like this:

So, each of those <dt>s, in this case, happen to be nicely tucked away to the left in the space that the margin-inline-start makes for the <dd>s. Which means that in extremely little CSS we can kick on that “stick sections” concept:

dt {
  position: sticky;
  top: 0;
  background: white;
  display: inline-block;
}

I love the simplicity of that.

And now that the core “functionality” works, the rest of the styling is just aesthetic sugar:

The version on 30 seconds of code uses a CSS Grid layout for the list items, which admittedly is more robust. I just thought it was interesting how close you can get in so little CSS without it. They also have a version where the <dt>s stretch the whole width which is also nice.


The post Sticky Definition Lists appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/sticky-definition-lists/

How to Implement and Style the Dialog Element

A look from Christian Kozalla on the <dialog> HTML element and using it to create a nice-looking and accessible modal.

I’m attracted to the <dialog> element as it’s one of those “you get a lot for free” elements (even more so than the beloved <details> element) and it’s so easy to get modal accessibility wrong (e.g. focus trapping) that having this sort of thing provided by a native element seems… great. ::backdrop is especially cool.

But is it too good to be true? Solid support isn’t there yet, with Safari not picking it up.

Christian mentions the polyfill from Google, which definitely helps bring basic functionality to otherwise non-supporting browsers.

The main problem is actual testing on a screen reader. Scott O’Hara has an article, “Having an open dialog,” which has been updated as recently as this very month (October 2021), in which he ultimately says, “[…] the dialog element and its polyfill are not suitable for use in production.” I don’t doubt Scott’s testing, but because most people just roll-their-own modal experiences paying little mind to accessibility at all, I wonder if the web would be better off if more people just used <dialog> (and the polyfill) anyway. Higher usage would likely trigger more browser attention and improvements.


The post How to Implement and Style the Dialog Element appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/how-to-implement-and-style-the-dialog-element/

Wednesday, October 27, 2021

Testing Vue Components With Cypress

Cypress is an automated test runner for browser-based applications and pages. I’ve used it for years to write end-to-end tests for web projects, and was happy to see recently that individual component testing had come to Cypress. I work on a large enterprise Vue application, and we already use Cypress for end-to-end tests. Most of our unit and component tests are written with Jest and Vue Test Utils.

Once component testing arrived in Cypress, my team was all in favor of upgrading and trying it out. You can learn a lot about how component testing works directly from the Cypress docs, so I’m going skip over some of the setup steps and focus on what it is like to work with component tests — what do they look like, how are we using them, and some Vue-specific gotchas and helpers we found.

Disclosure! At the time I wrote the first draft of this article, I was the front-end team lead at a large fleet management company where we used Cypress for testing. Since the time of writing, I’ve started working at Cypress, where I get to contribute to the open source test runner.

The Cypress component test runner is open, using Chrome to test a “Privacy Policy” component. Three columns are visible in the browser. The first contains a searchable list of component test spec files; the second shows the tests for the currently-spec; the last shows the component itself mounted in the browser. The middle column shows that two tests are passing.

All the examples mentioned here are valid at the time of writing using Cypress 8. It’s a new feature that’s still in alpha, and I wouldn’t be surprised if some of these details change in future updates.

If you already have a background in testing and component tests, you can skip right to our team’s experiences.

What a component test file looks like

For a simplified example, I’ve created a project that contains a “Privacy Policy” component. It has a title, body, and an acknowledgment button.

The Privacy Policy component has three areas. The title reads “Privacy Policy”; the body text reads “Information about privacy that you should read in detail,” and a blue button at the bottom reads “OK, I read it, sheesh.”

When the button is clicked, an event is emitted to let the parent component know that this has been acknowledged. Here it is deployed on Netlify.

Now here’s the general shape of a component test in Cypress that uses some of the feature’s we are going to talk about:

import { mount } from '@cypress/vue'; // import the vue-test-utils mount function
import PrivacyPolicyNotice from './PrivacyPolicyNotice.vue'; // import the component to test

describe('PrivacyPolicyNotice', () => {
 
 it('renders the title', () => {
    // mount the component by itself in the browser 🏗
    mount(PrivacyPolicyNotice); 
    
    // assert some text is present in the correct heading level 🕵️ 
    cy.contains('h1', 'Privacy Policy').should('be.visible'); 
  });

  it('emits a "confirm" event once when confirm button is clicked', () => {
    // mount the component by itself in the browser 🏗
    mount(PrivacyPolicyNotice);

    // this time let's chain some commands together
    cy.contains('button', '/^OK/') // find a button element starting with text 'OK' 🕵️
    .click() // click the button 🤞
    .vue() // use a custom command to go get the vue-test-utils wrapper 🧐
    .then((wrapper) => {
      // verify the component emitted a confirm event after the click 🤯
      expect(wrapper.emitted('confirm')).to.have.length(1) 
      // `emitted` is a helper from vue-test-utils to simplify accessing
      // events that have been emitted
    });
  });

});

This test makes some assertions about the user interface, and some about the developer interface (shoutout to Alex Reviere for expressing this division in the way that clicked for me). For the UI, we are targeting specific elements with their expected text content. For developers, we are testing what events are emitted. We are also implicitly testing that the component is a correctly formed Vue component; otherwise it would not mount successfully and all the other steps would fail. And by asserting specific kinds of elements for specific purposes, we are testing the accessibility of the component — if that accessible button ever becomes a non-focusable div, we’ll know about it.

Here’s how our test looks when I swap out the button for a div. This helps us maintain the expected keyboard behavior and assistive technology hints that come for free with a button element by letting us know if we accidentally swap it out:

The Cypress component test runner shows that one test is passing and one is failing. The failure warning is titled 'Assertion Error' and reads 'Timed out retrying after 4000ms: Expected to find content: '/^OK/' within the selector: 'button' but never did.'

A little groundwork

Now that we’ve seen what a component test looks like, let’s back up a little bit and talk about how this fits in to our overall testing strategy. There are many definitions for these things, so real quick, for me, in our codebase:

  • Unit tests confirm single functions behave as expected when used by a developer.
  • Component tests mount single UI components in isolation and confirm they behave as expected when used by an end-user and a developer.
  • End-to-end tests visit the application and perform actions and confirm the app as whole behaves correctly when used by an end-user only.

Finally, integration testing is a little more of a squishy term for me and can happen at any level — a unit that imports other functions, a component that imports other components, or indeed, an “end-to-end” test that mocks API responses and doesn’t reach the database, might all be considered integration tests. They test more than one part of an application working together, but not the entire thing. I’m not sure about the real usefulness of that as a category, since it seems very broad, but different people and organizations use these terms in other ways, so I wanted to touch on it.

For a longer overview of the different kinds of testing and how they relate to front-end work, you can check out “Front-End Testing is For Everyone” by Evgeny Klimenchenko.

Component tests

In the definitions above, the different testing layers are defined by who will be using a piece of code and what the contract is with that person. So as a developer, a function that formats the time should always return the correct result when I provide it a valid Date object, and should throw clear errors if I provide it something different as well. These are things we can test by calling the function on its own and verifying it responds correctly to various conditions, independent of any UI. The “developer interface” (or API) of a function is all about code talking to other code.

Now, let’s zoom in on component tests. The “contract” of a component is really two contracts:

  • To the developer using a component, the component is behaving correctly if the expected events are emitted based on user input or other activity. It’s also fair to include things like prop types and validation rules in our idea of “correct developer-facing behavior,” though those things can also be tested at a unit level. What I really want from a component test as a developer is to know it mounts, and sends the signals it is supposed to based on interactions.
  • To the user interacting with a component, it is behaving correctly if the UI reflects the state of the component at all times. This includes more than just the visual aspect. The HTML generated by the component is the foundation for its accessibility tree, and the accessibility tree provides the API for tools like screen readers to announce the content correctly, so for me the component is not “behaving correctly” if it does not render the correct HTML for the contents.

At this point it’s clear that component testing requires two kinds of assertions — sometimes we check Vue-specific things, like “how many events got emitted of a certain type?”, and sometimes we check user-facing things, like “did a visible success message actually end up on the screen though?”

It also feels like component level tests are a powerful documentation tool. The tests should assert all the critical features of a component — the defined behaviors that are depended on — and ignore details that aren’t critical. This means we can look to the tests to understand (or remember, six months or a year from now!) what a component’s expected behavior is. And, all going well, we can change any feature that’s not explicitly asserted by the test without having to rewrite the test. Design changes, animation changes, improving the DOM, all should be possible, and if a test does fail, it will be for a reason you care about, not because an element got moved from one part of the screen to another.

This last part takes some care when designing tests, and most especially, when choosing selectors for elements to interact with, so we’ll return to this topic later.

How Vue component tests work with and without Cypress

At a high level, a combination of Jest and the Vue Test Utils library has becomes more or less the standard approach to running component tests that I’ve seen out there.

Vue Test Utils gives us helpers to mount a component, give it its options, and mock out various things a component might depend on to run properly. It also provides a wrapper object around the mounted component to make it a little easier to make assertions about what’s going on with the component.

Jest is a great test runner and will stand up the mounted component using jsdom to simulate a browser environment.

Cypress’ component test runner itself uses Vue Test Utils to mount Vue components, so the main difference between the two approaches is context. Cypress already runs end-to-end tests in a browser, and component tests work the same way. This means we can see our tests run, pause them mid-test, interact with the app or inspect things that happened earlier in the run, and know that browser APIs that our application depends on are genuine browser behavior rather than the jsdom mocked versions of those same features.

Once the component is mounted, all the usual Cypress things that we have been doing in end-to-end tests apply, and a few pain points around selecting elements go away. Mainly, Cypress is going to handle simulating all the user interactions, and making assertions about the application’s response to those interactions. This covers the user-facing part of the component’s contract completely, but what about the developer-facing stuff, like events, props, and everything else? This is where Vue Test Utils comes back in. Within Cypress, we can access the wrapper that Vue Test Utils creates around the mounted component, and make assertions about it.

What I like about this is that we end up with Cypress and Vue Test Utils both being used for what they are really good at. We can test the component’s behavior as a user with no framework-specific code at all, and only dig into Vue Test Utils for mounting the component and checking specific framework behavior when we choose to. We’ll never have to await a Vue-specific $nextTick after doing some Vue-specific thing to update the state of a component. That was always the trickiest thing to explain to new developers on the team without Vue experience — when and why they would need to await things when writing a test for a Vue component.

Our experience of component testing

The advantages of component testing sounded great to us, but of course, in a large project very few things can be seamless out of the box, and as we got started with our tests, we ran into some issues. We run a large enterprise SPA built using Vue 2 and the Vuetify component library. Most of our work heavily uses Vuetify’s built-in components and styles. So, while the “test components by themselves” approach sounds nice, a big lesson learned was that we needed to set up some context for our components to be mounted in, and we needed to get Vuetify and some global styles happening as well, or nothing was going to work.

Cypress has a Discord where people can ask for help, and when I got stuck I asked questions there. Folks from the community —as well as Cypress team members — kindly directed me to example repos, code snippets, and ideas for solving our problems. Here’s a list of the little things we needed to understand in order to get our components to mount correctly, errors we encountered, and whatever else stands out as interesting or helpful:

Importing Vuetify

Through lurking in the Cypress Discord, I’d seen this example component test Vuetify repo by Bart Ledoux, so that was my starting point. That repo organizes the code into a fairly common pattern that includes a plugins folder, where a plugin exports an instance of Veutify. This is imported by the application itself, but it can also be imported by our test setup, and used when mounting the component being tested. In the repo a command is added to Cypress that will replace the default mount function with one that mounts a component with Vuetify.

Here is all the code needed to make that happen, assuming we did everything in commands.js and didn’t import anything from the plugins folder. We’re doing this with a custom command which means that instead of calling the Vue Test Utils mount function directly in our tests, we’ll actually call our own cy.mount command:

// the Cypress mount function, which wraps the vue-test-utils mount function
import { mount } from "@cypress/vue"; 
import Vue from 'vue';
import Vuetify from 'vuetify/lib/framework';

Vue.use(Vuetify);

// add a new command with the name "mount" to run the Vue Test Utils 
// mount and add Vuetify
Cypress.Commands.add("mount", (MountedComponent, options) => {
  return mount(MountedComponent, {
    vuetify: new Vuetify({});, // the new Vuetify instance
    ...options, // To override/add Vue options for specific tests
  });
});

Now we will always have Vuetify along with our components when mounted, and we can still pass in all the other options we need to for that component itself. But we don’t need to manually add Veutify each time.

Adding attributes required by Vuetify

The only problem with the new mount command above is that, to work correctly, Vuetify components expect to be rendered in a certain DOM context. Apps using Vuetify wrap everything in a <v-app> component that represents the root element of the application. There are a couple of ways to handle this but the simplest is to add some setup to our command itself before it mounts a component.

Cypress.Commands.add("mount", (MountedComponent, options) => {
  // get the element that our mounted component will be injected into
  const root = document.getElementById("__cy_root");

  // add the v-application class that allows Vuetify styles to work
  if (!root.classList.contains("v-application")) {
    root.classList.add("v-application");
  }

  // add the data-attribute — Vuetify selector used for popup elements to attach to the DOM
  root.setAttribute('data-app', 'true');  

return mount(MountedComponent, {
    vuetify: new Vuetify({}), 
    ...options,
  });
});

This takes advantage of the fact that Cypress itself has to create some root element to actually mount our component to. That root element is the parent of our component, and it has the ID __cy_root. This gives us a place to easily add the correct classes and attributes that Vuetify expects to find. Now components that use Vuetify components will look and behave correctly.

One other thing we noticed after some testing is that the required class of v-application has a display property of flex. This makes sense in a full app context using Vuetify’s container system, but had some unwanted visual side effects for us when mounting single components — so we added one more line to override that style before mounting the component:

root.setAttribute('style', 'display: block');

This cleared up the occasional layout issues and then we were truly done tweaking the surrounding context for mounting components.

Getting spec files where we want them

A lot of the examples out there show a cypress.json config file like this one for component testing:

{
  "fixturesFolder": false,
  "componentFolder": "src/components",
  "testFiles": "**/*.spec.js"
}

That is actually pretty close to what we want since the testFiles property accepts a glob pattern. This one says, Look in any folder for files ending in .spec.js. In our case, and probably many others, the project’s node_modules folder contained some irrelevant spec.js files that we excluded by prefixing !(node_modules) like this:

"testFiles": "!(node_modules)**/*.spec.js"

Before settling on this solution, when experimenting, we had set this to a specific folder where component tests would live, not a glob pattern that could match them anywhere. Our tests live right alongside our components, so that could have been fine, but we actually have two independent components folders as we package up and publish a small part of our app to be used in other projects at the company. Having made that change early, I admit I sure did forget it had been a glob to start with and was starting to get off course before popping into the Discord, where I got a reminder and figured it out. Having a place to quickly check if something is the right approach was helpful many times.

Command file conflict

Following the pattern outlined above to get Vuetify working with our component tests produced a problem. We had piled all this stuff together in the same commands.js file that we used for regular end-to-end tests. So while we got a couple of component tests running, our end-to-end tests didn’t even start. There was an early error from one of the imports that was only needed for component testing.

I was recommended a couple of solutions but on the day, I chose to just extract the mounting command and its dependencies into its own file, and imported it only where needed in the component tests themselves. Since this was the only source of any problem running both sets of tests, it was a clean way to take that out of the the end-to-end context, and it works just fine as a standalone function. If we have other issues, or next time we are doing cleanup, we would probably follow the main recommendation given, to have two separate command files and share the common pieces between them.

Accessing the Vue Test Utils wrapper

In the context of a component test, the Vue Test Utils wrapper is available under Cypress.vueWrapper. When accessing this to make assertions, it helps to use cy.wrap to make the result chain-able like other commands accessed via cy. Jessica Sachs adds a short command in her example repo to do this. So, once again inside commands,js, I added the following:

Cypress.Commands.add('vue', () => {
  return cy.wrap(Cypress.vueWrapper);
});

This can be used in a test, like this:

mount(SomeComponent)
  .contains('button', 'Do the thing once')
  .click()
  .should('be.disabled')
  .vue()
  .then((wrapper) => {
    // the Vue Test Utils `wrapper` has an API specifically setup for testing: 
    // https://vue-test-utils.vuejs.org/api/wrapper/#properties
    expect(wrapper.emitted('the-thing')).to.have.length(1);
  });

This starts to read very naturally to me and clearly splits up when we are working with the UI compared to when we are inspecting details revealed through the Vue Test Utils wrapper. It also emphasizes that, like lots of Cypress, to get the most out of it, it’s important to understand the tools it leverages, not just Cypress itself. Cypress wraps Mocha, Chai, and various other libraries. In this case, it’s useful to understand that Vue Test Utils is a third-party open source solution with its own entire set of documentation, and that inside the then callback above, we are in Vue Test Utils Land — not Cypress Land — so that we go to the right place for help and documentation.

Challenges

Since this has been a recent exploration, we have not added the Cypress component tests to our CI/CD pipelines yet. Failures will not block a pull request, and we haven’t looked at adding the reporting for these tests. I don’t expect any surprises there, but it’s worth mentioning that we haven’t completed integrating these into our whole workflow. I can’t speak to it specifically.

It’s also relatively early days for the component test runner and there are a few hiccups. At first, it seemed like every second test run would show a linter error and need to be manually refreshed. I didn’t get to the bottom of that, and then it fixed itself (or was fixed by a newer Cypress release). I’d expect a new tool to have potential issues like this.

One other stumbling block about component testing in general is that, depending on how your component works, it can be difficult to mount it without a lot of work mocking other parts of your system. If the component interacts with multiple Vuex modules or uses API calls to fetch its own data, you need to simulate all of that when you mount the component. Where end-to-end tests are almost absurdly easy to get up and running on any project that runs in the browser, component tests on existing components are a lot more sensitive to your component design.

This is true of anything that mounts components in isolation, like Storybook and Jest, which we’ve also used. It’s often when you attempt to mount components in isolation that you realize just how many dependencies your components actually have, and it can seem like a lot of effort is needed just to provide the right context for mounting them. This nudges us towards better component design in the long run, with components that are easier to test and while touching fewer parts of the codebase.

For this reason, I’d suggest if you haven’t already got component tests, and so aren’t sure what you need to mock in order to mount your component, choose your first component tests carefully, to limit the number of factors you have to get right before you can see the component in the test runner. Pick a small, presentational component that renders content provided through props or slots, to see it a component test in action before getting into the weeds on dependencies.

Benefits

The component test runner has worked out well for our team. We already have extensive end-to-end tests in Cypress, so the team is familiar with how to spin up new tests and write user interactions. And we have been using Vue Test Utils for individual component testing as well. So there was not actually too much new to learn here. The initial setup issues could have been frustrating, but there are plenty of friendly people out there who can help work through issues, so I’m glad I used the “asking for help” superpower.

I would say there are two main benefits that we’ve found. One is the consistent approach to the test code itself between levels of testing. This helps because there’s no longer a mental shift to think about subtle differences between Jest and Cypress interactions, browser DOM vs jsdom and similar issues.

The other is being able to develop components in isolation and getting visual feedback as we go. By setting up all the variations of a component for development purposes, we get the outline of the UI test ready, and maybe a few assertions too. It feels like we get more value out of the testing process up front, so it’s less like a bolted-on task at the end of a ticket.

This process is not quite test-driven development for us, though we can drift into that, but it’s often “demo-driven” in that we want to showcase the states of a new piece of UI, and Cypress is a pretty good way to do that, using cy.pause() to freeze a running test after specific interactions and talk about the state of the component. Developing with this in mind, knowing that we will use the tests to walk through the components features in a demo, helps organize the tests in a meaningful way and encourages us to cover all the scenarios we can think of at development time, rather than after.

Conclusion

The mental model for what exactly Cypress as whole does was tricky for me to when I first learned about it, because it wraps so many other open source tools in the testing ecosystem. You can get up and running quickly with Cypress without having a deep knowledge of what other tools are being leveraged under the hood.

This meant that when things went wrong, I remember not being sure which layer I should think about — was something not working because of a Mocha thing? A Chai issue? A bad jQuery selector in my test code? Incorrect use of a Sinon spy? At a certain point, I needed to step back and learn about those individual puzzle pieces and what exact roles they were playing in my tests.

This is still the case with component testing, and now there is an extra layer: framework-specific libraries to mount and test components. In some ways, this is more overhead and more to learn. On the other hand, Cypress integrates these tools in a coherent way and manages their setup so we can avoid a whole unrelated testing setup just for component tests. For us, we already wanted to mount components independently for testing with Jest, and for use in Storybook, so we figured out a lot of the necessary mocking ideas ahead of time, and tended to favor well-separated components with simple props/events based interfaces for that reason.

On balance, we like working with the test runner, and I feel like I’m seeing more tests (and more readable test code!) showing up in pull requests that I review, so to me that’s a sign that we’ve moved in a good direction.


The post Testing Vue Components With Cypress appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/testing-vue-components-with-cypress/

On Browser-Specific URL Schemes

We’ve covered URL schemes:

A URL Scheme is like “http://…” or “ftp://…”. Those seem like a very low-level concept that you don’t have much control over, but actually, you do!

I’d call it non-trivial, but developers can register new URL schemes in apps that users install. Back in 2017, Microsoft Edge did this:

microsoft-edge:// 

If you use that, the behavior is to open the URL in Microsoft Edge — even if you’ve chosen a different default browser. So if I, as a blogger, wanted to essentially force you to use Edge for this site, I could, by starting every single URL with this URL scheme. I won’t, but I could. And so could Microsoft.

At the time, Daniel Aleksandersen wrote a program called EdgeDefelector to circumvent that behavior and explained:

I don’t hate Microsoft Edge — maybe you do! — but I do believe users who have bothered to configure a different default web browser should be allowed to keep using that default web browser. 

This has come back into the public eye a bit as the Brave browser now supports the microsoft-edge:// URL scheme. Apparently, not only does an app need to register a URL scheme, but other apps that support clicks-on-links need to honor it too. Firefox is also thinking of adding it. I think the risk of not supporting the URL scheme is that clicks on links like that could do nothing instead of actually opening the URL.

A lot of the talk is about Windows 11. But here on my Mac, I see this URL scheme do what it intends across all these browsers.

Safari
Chrome
Firefox
Brave

Daniel goes further:

So, how did we get here? Until the release of iOS version 14 in September 2020, you couldn’t change the default web browser on iPhones and iPads. Google has many apps for iOS, including a shell for its Chrome browser. To tie all its apps together, Google introduced a googlechrome: URL scheme in February 2014. It could use these links to direct you from its Search or Mail app and over to Chrome instead of Apple’s Safari browser.

Here’s my iPhone 13 opening googlechrome://css-tricks.com with and without Google Chrome installed.

iOS Safari with Google Chrome installed
iOS Safari without Google Chrome installed

Seems like that would be Google’s sin, but it is apparently Apple that allowed it on iOS. Daniel once more:

The original sin was Apple’s, but Microsoft is gulping the juice of the apple with gusto.

I’m not as boned up on all this as I should be, but I think if I made software that was involved here, I’d be tempted to intercept these URL schemes and have them open in the browser the user is already in. The web is the web, there should be no reason any given URL has to open in any specific browser.


The post On Browser-Specific URL Schemes appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.



source https://css-tricks.com/on-browser-specific-url-schemes/