Monty  Boehm

Monty Boehm

1684839240

Enzyme: JavaScript Testing utilities for React

Enzyme

Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output.

Enzyme's API is meant to be intuitive and flexible by mimicking jQuery's API for DOM manipulation and traversal.

Upgrading from Enzyme 2.x or React < 16

Are you here to check whether or not Enzyme is compatible with React 16? Are you currently using Enzyme 2.x? Great! Check out our migration guide for help moving on to Enzyme v3 where React 16 is supported.

Installation

To get started with enzyme, you can simply install it via npm. You will need to install enzyme along with an Adapter corresponding to the version of react (or other UI Component library) you are using. For instance, if you are using enzyme with React 16, you can run:

npm i --save-dev enzyme enzyme-adapter-react-16

Each adapter may have additional peer dependencies which you will need to install as well. For instance, enzyme-adapter-react-16 has peer dependencies on react and react-dom.

At the moment, Enzyme has adapters that provide compatibility with React 16.x, React 15.x, React 0.14.x and React 0.13.x.

The following adapters are officially provided by enzyme, and have the following compatibility with React:

Enzyme Adapter PackageReact semver compatibility
enzyme-adapter-react-16^16.4.0-0
enzyme-adapter-react-16.3~16.3.0-0
enzyme-adapter-react-16.2~16.2
enzyme-adapter-react-16.1~16.0.0-0 || ~16.1
enzyme-adapter-react-15^15.5.0
enzyme-adapter-react-15.415.0.0-0 - 15.4.x
enzyme-adapter-react-14^0.14.0
enzyme-adapter-react-13^0.13.0

Finally, you need to configure enzyme to use the adapter you want it to use. To do this, you can use the top level configure(...) API.

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

3rd Party Adapters

It is possible for the community to create additional (non-official) adapters that will make enzyme work with other libraries. If you have made one and it's not included in the list below, feel free to make a PR to this README and add a link to it! The known 3rd party adapters are:

Adapter PackageFor LibraryStatus
enzyme-adapter-preact-purepreact(stable)
enzyme-adapter-infernoinferno(work in progress)

Running Enzyme Tests

Enzyme is unopinionated regarding which test runner or assertion library you use, and should be compatible with all major test runners and assertion libraries out there. The documentation and examples for enzyme use Mocha and Chai, but you should be able to extrapolate to your framework of choice.

If you are interested in using enzyme with custom assertions and convenience functions for testing your React components, you can consider using:

Using Enzyme with Mocha

Using Enzyme with Karma

Using Enzyme with Browserify

Using Enzyme with SystemJS

Using Enzyme with Webpack

Using Enzyme with JSDOM

Using Enzyme with React Native

Using Enzyme with Jest

Using Enzyme with Lab

Using Enzyme with Tape and AVA

Basic Usage

Shallow Rendering

import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';

import MyComponent from './MyComponent';
import Foo from './Foo';

describe('<MyComponent />', () => {
  it('renders three <Foo /> components', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find(Foo)).to.have.lengthOf(3);
  });

  it('renders an `.icon-star`', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find('.icon-star')).to.have.lengthOf(1);
  });

  it('renders children when passed in', () => {
    const wrapper = shallow((
      <MyComponent>
        <div className="unique" />
      </MyComponent>
    ));
    expect(wrapper.contains(<div className="unique" />)).to.equal(true);
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = shallow(<Foo onButtonClick={onButtonClick} />);
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });
});

Read the full API Documentation

Full DOM Rendering

import React from 'react';
import sinon from 'sinon';
import { expect } from 'chai';
import { mount } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('allows us to set props', () => {
    const wrapper = mount(<Foo bar="baz" />);
    expect(wrapper.props().bar).to.equal('baz');
    wrapper.setProps({ bar: 'foo' });
    expect(wrapper.props().bar).to.equal('foo');
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = mount((
      <Foo onButtonClick={onButtonClick} />
    ));
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });

  it('calls componentDidMount', () => {
    sinon.spy(Foo.prototype, 'componentDidMount');
    const wrapper = mount(<Foo />);
    expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1);
    Foo.prototype.componentDidMount.restore();
  });
});

Read the full API Documentation

Static Rendered Markup

import React from 'react';
import { expect } from 'chai';
import { render } from 'enzyme';

import Foo from './Foo';

describe('<Foo />', () => {
  it('renders three `.foo-bar`s', () => {
    const wrapper = render(<Foo />);
    expect(wrapper.find('.foo-bar')).to.have.lengthOf(3);
  });

  it('renders the title', () => {
    const wrapper = render(<Foo title="unique" />);
    expect(wrapper.text()).to.contain('unique');
  });
});

Read the full API Documentation

React Hooks support

Enzyme supports react hooks with some limitations in .shallow() due to upstream issues in React's shallow renderer:

useEffect() and useLayoutEffect() don't get called in the React shallow renderer. Related issue

useCallback() doesn't memoize callback in React shallow renderer. Related issue

ReactTestUtils.act() wrap

If you're using React 16.8+ and .mount(), Enzyme will wrap apis including .simulate(), .setProps(), .setContext(), .invoke() with ReactTestUtils.act() so you don't need to manually wrap it.

A common pattern to trigger handlers with .act() and assert is:

const wrapper = mount(<SomeComponent />);
act(() => wrapper.prop('handler')());
wrapper.update();
expect(/* ... */);

We cannot wrap the result of .prop() (or .props()) with .act() in Enzyme internally since it will break the equality of the returned value. However, you could use .invoke() to simplify the code:

const wrapper = mount(<SomeComponent />);
wrapper.invoke('handler')();
expect(/* ... */);

Future

Enzyme Future

Contributing

See the Contributors Guide

In the wild

Organizations and projects using enzyme can list themselves here.


Download Details:

Author: enzymejs
Source Code: https://github.com/enzymejs/enzyme 
License: MIT license

#react #testing #mocha #enzyme #jest #test 

Enzyme: JavaScript Testing utilities for React

Use Mocking Package for Dio intended to Be Used In Tests For Flutter

Description

http_mock_adapter is a simple to use mocking package for Dio intended to be used in tests. It provides various types and methods to declaratively mock request-response communication.

Usage

Here is a very basic usage scenario:

import 'package:dio/dio.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart';

void main() async {
  final dio = Dio(BaseOptions());
  final dioAdapter = DioAdapter(dio: dio);

  const path = 'https://example.com';

  dioAdapter.onGet(
    path,
    (server) => server.reply(
      200,
      {'message': 'Success!'},
      // Reply would wait for one-sec before returning data.
      delay: const Duration(seconds: 1),
    ),
  );

  final response = await dio.get(path);

  print(response.data); // {message: Success!}
}

Real-world example

The intended usage domain is in tests when trying to simulate behavior of request-response communication with a server. The example portrays a decent use case of how one might make good use of the package.

Installing

Quick install

You can quickly install the package from the command-line:

With dart:

$ dart pub add --dev http_mock_adapter
...

With flutter:

$ flutter pub add --dev http_mock_adapter
...

Manual install

Depend on it

Add this to your package's pubspec.yaml file:

dev_dependencies:
  http_mock_adapter: ^0.4.4

Install it

You can then install the package from the command-line:

With dart:

$ dart pub get
...

With flutter:

$ flutter pub get
...

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:http_mock_adapter/http_mock_adapter.dart';

Changelog

All notable changes to this project will be documented in the CHANGELOG.md file.

Authors

See the AUTHORS file for information regarding the authors of the project.

License

http-mock-adapter is licensed under the permissive MIT License (LICENSE).

Contribution

For information regarding contributions, please refer to CONTRIBUTING.md file.

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add http_mock_adapter

With Flutter:

 $ flutter pub add http_mock_adapter

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  http_mock_adapter: ^0.4.4

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:http_mock_adapter/http_mock_adapter.dart';

example/main.dart

import 'package:dio/dio.dart';
import 'package:http_mock_adapter/http_mock_adapter.dart';
import 'package:test/test.dart';

void main() async {
  late Dio dio;
  late DioAdapter dioAdapter;

  Response<dynamic> response;

  group('Accounts', () {
    const baseUrl = 'https://example.com';

    const userCredentials = <String, dynamic>{
      'email': 'test@example.com',
      'password': 'password',
    };

    setUp(() {
      dio = Dio(BaseOptions(baseUrl: baseUrl));
      dioAdapter = DioAdapter(
        dio: dio,

        // [FullHttpRequestMatcher] is a default matcher class
        // (which actually means you haven't to pass it manually) that matches entire URL.
        //
        // Use [UrlRequestMatcher] for matching request based on the path of the URL.
        //
        // Or create your own http-request matcher via extending your class from  [HttpRequestMatcher].
        // See -> issue:[124] & pr:[125]
        matcher: const FullHttpRequestMatcher(),
      );
    });

    test('signs up user', () async {
      const route = '/signup';

      dioAdapter.onPost(
        route,
        (server) => server.reply(
          201,
          null,
          // Adds one-sec delay to reply method.
          // Basically, I'd wait for one second before returning reply data.
          // See -> issue:[106] & pr:[126]
          delay: const Duration(seconds: 1),
        ),
        data: userCredentials,
      );

      // Returns a response with 201 Created success status response code.
      response = await dio.post(route, data: userCredentials);

      expect(response.statusCode, 201);
    });

    test('signs in user and fetches account information', () async {
      const signInRoute = '/signin';
      const accountRoute = '/account';

      const accessToken = <String, dynamic>{
        'token': 'ACCESS_TOKEN',
      };

      final headers = <String, dynamic>{
        'Authentication': 'Bearer $accessToken',
      };

      const userInformation = <String, dynamic>{
        'id': 1,
        'email': 'test@example.com',
        'password': 'password',
        'email_verified': false,
      };

      dioAdapter
        ..onPost(
          signInRoute,
          (server) => server.throws(
            401,
            DioError(
              requestOptions: RequestOptions(
                path: signInRoute,
              ),
            ),
          ),
        )
        ..onPost(
          signInRoute,
          (server) => server.reply(200, accessToken),
          data: userCredentials,
        )
        ..onGet(
          accountRoute,
          (server) => server.reply(200, userInformation),
          headers: headers,
        );

      // Throws without user credentials.
      expect(
        () async => await dio.post(signInRoute),
        throwsA(isA<DioError>()),
      );

      // Returns an access token if user credentials are provided.
      response = await dio.post(signInRoute, data: userCredentials);

      expect(response.data, accessToken);

      // Returns user information if an access token is provided in headers.
      response = await dio.get(
        accountRoute,
        options: Options(headers: headers),
      );

      expect(response.data, userInformation);
    });
  });
}

Download Details:

Author: lomsa.com

Source Code: https://github.com/lomsa-dev/http-mock-adapter

#flutter #android #ios #http #mock #testing #test 

Use Mocking Package for Dio intended to Be Used In Tests For Flutter
Bongani  Ngema

Bongani Ngema

1682609520

How to Test your Drupal website with Cypress

Testing makes everything better. Learn how to use Cypress for your Drupal website.

If you don't include tests in your Drupal development, chances are it's because you think it adds complexity and expense without benefit. Cypress is an open source tool with many benefits:

  • Reliably tests anything that runs in a web browser
  • Works on any web platform (it's great for testing projects using front-end technologies like React)
  • Highly extensible
  • Increasingly popular
  • Easy to learn and implement
  • Protects against regression as your projects become more complex
  • Can make your development process more efficient

This article covers three topics to help you start testing your Drupal project using Cypress:

  1. Installing Cypress
  2. Writing and running basic tests using Cypress
  3. Customizing Cypress for Drupal

Install Cypress

For the purposes of this tutorial I'm assuming that you have built a local dev environment for your Drupal project using the `drupal/recommended-project` project. Although details on creating such a project are outside of the scope of this piece, I recommend Getting Started with Lando and Drupal 9.

Your project has at least this basic structure:

vendor/
web/
.editorconfig
.gitattributes
composer.json
composer.lock

The cypress.io site has complete installation instructions for various environments. For this article, I installed Cypress using npm.

Initialize your project using the command npm init. Answer the questions that Node.js asks you, and then you will have a package.json file that looks something like this:

{
  "name": "cypress",
  "version": "1.0.0",
  "description": "Installs Cypress in a test project.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Install Cypress in your project:

$ npm install cypress --save-dev

Run Cypress for the first time:

$ npx cypress open

Because you haven't added a config or any scaffolding files to Cypress, the Cypress app displays the welcome screen to help you configure the project. To configure your project for E2E (end-to-end) testing, click the Not Configured button for E2E Testing. Cypress adds some files to your project:

cypress/
node_modules/
vendor/ 
web/
.editorconfig
.gitattributes
composer.json
composer.lock
cypress.config.js
package-lock.json
package.json

Click Continue and choose your preferred browser for testing. Click Start E2E Testing in [your browser of choice]. I'm using a Chromium-based browser for this article.

In a separate window, a browser opens to the Create your first spec page:

Cypress in a web browser

(Jordan Graham, CC BY-SA 4.0)

Click on the Scaffold example specs button to create a couple of new folders with example specs to help you understand how to use Cypress. Read through these in your code editor, and you'll likely find the language (based on JavaScript) intuitive and easy to follow.

Click on any in the test browser. This reveals two panels. On the left, a text panel shows each step in the active spec. On the right, a simulated browser window shows the actual user experience as Cypress steps through the spec.

Open the cypress.config.js file in your project root and change it as follows:

const { defineConfig } = require("cypress");
 
module.exports = defineConfig({
  component: {
    fixturesFolder: "cypress/fixtures",
    integrationFolder: "cypress/integration",
    pluginsFile: "cypress/plugins/index.js",
    screenshotsFolder: "cypress/screenshots",
    supportFile: "cypress/support/e2e.js",
    videosFolder: "cypress/videos",
    viewportWidth: 1440,
    viewportHeight: 900,
  },

  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
    baseUrl: "https://[your-local-dev-url]",
    specPattern: "cypress/**/*.{js,jsx,ts,tsx}",
    supportFile: "cypress/support/e2e.js",
    fixturesFolder: "cypress/fixtures"
   },
 });

Change the baseUrl to your project's URL in your local dev environment.

These changes tell Cypress where to find its resources and how to find all of the specs in your project.

Write and run basic tests using Cypress

Create a new directory called integration in your /cypress directory. Within the integration directory, create a file called test.cy.js:

cypress/
├─ e2e/
├─ fixtures/
├─ integration/ 
│  ├─ test.cy.js
├─ support/ 
node_modules/
vendor/
web/
.editorconfig
.gitattributes
composer.json
composer.lock
cypress.config.js
package-lock.json
package.json

Add the following contents to your test.cy.js file:

describe('Loads the front page', () => {
  it('Loads the front page', () => {
    cy.visit('/')
    cy.get('h1.page-title')
      .should('exist')
  });
});
 
describe('Tests logging in using an incorrect password', () => {
  it('Fails authentication using incorrect login credentials', () => {
    cy.visit('/user/login')
    cy.get('#edit-name')
      .type('Sir Lancelot of Camelot')
    cy.get('#edit-pass')
      .type('tacos')
    cy.get('input#edit-submit')
      .contains('Log in')
      .click()
    cy.contains('Unrecognized username or password.')
  });
});

When you click on test.cy.js in the Cypress application, watch each test description on the left as Cypress performs the steps in each describe() section.

This spec demonstrates how to tell Cypress to navigate your website, access HTML elements by ID, enter content into input elements, and submit the form. This process is how I discovered that I needed to add the assertion that the <input id="edit-submit"> element contains the text Log in before the input was clickable. Apparently, the flex styling of the submit input impeded Cypress' ability to "see" the input, so it couldn't click on it. Testing really works!

Customize Cypress for Drupal

You can write your own custom Cypress commands, too. Remember the supportFile entry in the cypress.config.js file? It points to a file that Cypress added, which in turn imports the ./commands files. Incidentally, Cypress is so clever that when importing logic or data fixtures, you don't need to specify the file extension, so you import ./commands, not ./commands.js. Cypress looks for any of a dozen or so popular file extensions and understands how to recognize and parse each of them.

Enter commands into commands.js to define them:

/**
 * Logs out the user.
 */
 
Cypress.Commands.add('drupalLogout', () => {
  cy.visit('/user/logout');
})
 
/**
 * Basic user login command. Requires valid username and password.
 *
 * @param {string} username
 *   The username with which to log in.
 * @param {string} password
 *   The password for the user's account.
 */
 
Cypress.Commands.add('loginAs', (username, password) => {
  cy.drupalLogout();
  cy.visit('/user/login');
  cy.get('#edit-name')
    .type(username);
  cy.get('#edit-pass').type(password, {
    log: false,
  });
 
  cy.get('#edit-submit').contains('Log in').click();
});

This example defines a custom Cypress command called drupalLogout(), which you can use in any subsequent logic, even other custom commands. To log a user out, call cy.drupalLogout(). This is the first event in the custom command loginAs to ensure that Cypress is logged out before attempting to log in as a specific user.

Using environment variables, you can even create a Cypress command called drush(), which you can use to execute Drush commands in your tests or custom commands. Look at how simple this makes it to define a custom Cypress command that logs a user in using their UID:

/**
* Logs a user in by their uid via drush uli.
*/
 
Cypress.Commands.add('loginUserByUid', (uid) => {
 cy.drush('user-login', [], { uid, uri: Cypress.env('baseUrl') })
   .its('stdout')
   .then(function (url) {
     cy.visit(url);
   });
});

This example uses the drush user-login command (drush uli for short) and takes the authenticated user to the site's base URL.

Consider the security benefit of never reading or storing user passwords in your testing. Personally, I find it amazing that a front-end technology like Cypress can execute Drush commands, which I've always thought of as being very much on the back end.

Testing, testing

There's a lot more to Cypress, like fixtures (files that hold test data) and various tricks for navigating the sometimes complex data structures that produce a website's user interface. For a look into what's possible, watch the Cypress Testing for Drupal Websites webinar, particularly the section on fixtures that begins at 18:33. That webinar goes into greater detail about some interesting use cases, including an Ajax-enabled form. Once you start using it, feel free to use or fork Aten's public repository of Cypress Testing for Drupal.

Happy testing!

Original article source at: https://opensource.com/

#cypress #test #drupal #website 

How to Test your Drupal website with Cypress

Как протестировать свой сайт на Drupal с помощью Cypress

Тестирование делает все лучше. Узнайте, как использовать Cypress для вашего сайта на Drupal.

Если вы не включаете тесты в свою разработку Drupal, скорее всего, это потому, что вы думаете, что это усложняет и увеличивает расходы без пользы. Cypress — это инструмент с открытым исходным кодом, обладающий множеством преимуществ:

  • Надежно тестирует все, что работает в веб-браузере
  • Работает на любой веб-платформе (отлично подходит для тестирования проектов с использованием передовых технологий, таких как React ) .
  • Расширяемый
  • все более популярным
  • Простота в освоении и реализации
  • Защищает от регрессии по мере усложнения ваших проектов
  • Может сделать ваш процесс разработки более эффективным

В этой статье рассматриваются три темы, которые помогут вам начать тестирование вашего проекта Drupal с помощью Cypress:

  1. Установка Кипариса
  2. Написание и запуск базовых тестов с помощью Cypress
  3. Настройка Cypress для Drupal

Установить Кипарис

Для целей этого руководства я предполагаю, что вы создали локальную среду разработки для своего проекта Drupal, используя проект `drupal/recommended-project`. Хотя подробности создания такого проекта выходят за рамки этой статьи, я рекомендую  Начало работы с Lando и Drupal 9 .

Ваш проект имеет по крайней мере эту базовую структуру:

vendor/
web/
.editorconfig
.gitattributes
composer.json
composer.lock

На сайте cypress.io есть полные инструкции по установке для различных сред. Для этой статьи я установил Cypress с помощью npm .

Инициализируйте свой проект с помощью команды npm init. Ответьте на вопросы, которые задает вам Node.js, и тогда у вас будет файл package.json, который выглядит примерно так:

{
  "name": "cypress",
  "version": "1.0.0",
  "description": "Installs Cypress in a test project.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Установите Cypress в свой проект:

$ npm install cypress --save-dev

Запустите Cypress в первый раз:

$ npx cypress open

Поскольку вы не добавили конфигурацию или какие-либо файлы поддержки в Cypress, приложение Cypress отображает экран приветствия, чтобы помочь вам настроить проект. Чтобы настроить проект для E2E (сквозного) тестирования, нажмите кнопку «Не настроено» для E2E-тестирования. Cypress добавляет в ваш проект несколько файлов:

cypress/
node_modules/
vendor/ 
web/
.editorconfig
.gitattributes
composer.json
composer.lock
cypress.config.js
package-lock.json
package.json

Нажмите «Продолжить» и выберите предпочитаемый браузер для тестирования. Нажмите «Начать E2E-тестирование» в [выбранном вами браузере] . Для этой статьи я использую браузер на основе Chromium.

В отдельном окне браузер откроет страницу Create your first spec :

Кипарис в веб-браузере

(Джордан Грэм, CC BY-SA 4.0)

Нажмите на кнопку примеров спецификаций Scaffold , чтобы создать пару новых папок с примерами спецификаций, которые помогут вам понять, как использовать Cypress. Прочтите их в своем редакторе кода, и вы, вероятно, обнаружите, что язык (основанный на JavaScript) интуитивно понятен и прост в использовании.

Нажмите на любой в тестовом браузере. Это показывает две панели. Слева текстовая панель показывает каждый шаг активной спецификации. Справа смоделированное окно браузера показывает реальный пользовательский опыт, когда Cypress проходит через спецификацию.

Откройте cypress.config.jsфайл в корне вашего проекта и измените его следующим образом:

const { defineConfig } = require("cypress");
 
module.exports = defineConfig({
  component: {
    fixturesFolder: "cypress/fixtures",
    integrationFolder: "cypress/integration",
    pluginsFile: "cypress/plugins/index.js",
    screenshotsFolder: "cypress/screenshots",
    supportFile: "cypress/support/e2e.js",
    videosFolder: "cypress/videos",
    viewportWidth: 1440,
    viewportHeight: 900,
  },

  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
    baseUrl: "https://[your-local-dev-url]",
    specPattern: "cypress/**/*.{js,jsx,ts,tsx}",
    supportFile: "cypress/support/e2e.js",
    fixturesFolder: "cypress/fixtures"
   },
 });

Измените baseUrlURL-адрес вашего проекта в локальной среде разработки.

Эти изменения сообщают Cypress, где найти свои ресурсы и как найти все спецификации в вашем проекте.

Пишите и запускайте базовые тесты с помощью Cypress.

Создайте новый каталог с именем integrationв вашем /cypressкаталоге. В integrationкаталоге создайте файл с именем test.cy.js:

cypress/
├─ e2e/
├─ fixtures/
├─ integration/ 
│  ├─ test.cy.js
├─ support/ 
node_modules/
vendor/
web/
.editorconfig
.gitattributes
composer.json
composer.lock
cypress.config.js
package-lock.json
package.json

Добавьте в файл следующее содержимое test.cy.js:

describe('Loads the front page', () => {
  it('Loads the front page', () => {
    cy.visit('/')
    cy.get('h1.page-title')
      .should('exist')
  });
});
 
describe('Tests logging in using an incorrect password', () => {
  it('Fails authentication using incorrect login credentials', () => {
    cy.visit('/user/login')
    cy.get('#edit-name')
      .type('Sir Lancelot of Camelot')
    cy.get('#edit-pass')
      .type('tacos')
    cy.get('input#edit-submit')
      .contains('Log in')
      .click()
    cy.contains('Unrecognized username or password.')
  });
});

Когда вы нажимаете test.cy.jsв приложении Cypress, смотрите описание каждого теста слева, поскольку Cypress выполняет шаги в каждом describe()разделе.

Эта спецификация демонстрирует, как заставить Cypress перемещаться по вашему веб-сайту, получать доступ к элементам HTML по идентификатору, вводить содержимое в элементы ввода и отправлять форму. Именно в этом процессе я обнаружил, что мне нужно добавить утверждение, что элемент <input id="edit-submit">содержит текст «Войти» , прежде чем ввод будет доступен для клика. По-видимому, гибкий стиль ввода для отправки мешал Cypress «видеть» ввод, поэтому он не мог щелкнуть по нему. Тестирование действительно работает!

Настроить Cypress для Drupal

Вы также можете написать свои собственные команды Cypress. Помните supportFileзапись в cypress.config.jsфайле? Он указывает на файл, добавленный Cypress, который, в свою очередь, импортирует файлы ./commands. Кстати, Cypress настолько умен, что при импорте логики или фикстур данных вам не нужно указывать расширение файла, поэтому вы импортируете ./commands, а не ./commands.js. Cypress ищет любое из дюжины или около того популярных расширений файлов и понимает, как распознавать и анализировать каждое из них.

Введите команды, commands.jsчтобы определить их:

/**
 * Logs out the user.
 */
 
Cypress.Commands.add('drupalLogout', () => {
  cy.visit('/user/logout');
})
 
/**
 * Basic user login command. Requires valid username and password.
 *
 * @param {string} username
 *   The username with which to log in.
 * @param {string} password
 *   The password for the user's account.
 */
 
Cypress.Commands.add('loginAs', (username, password) => {
  cy.drupalLogout();
  cy.visit('/user/login');
  cy.get('#edit-name')
    .type(username);
  cy.get('#edit-pass').type(password, {
    log: false,
  });
 
  cy.get('#edit-submit').contains('Log in').click();
});

В этом примере определяется пользовательская команда Cypress с именем drupalLogout(), которую вы можете использовать в любой последующей логике, даже в других пользовательских командах. Чтобы выйти из системы, вызовите cy.drupalLogout(). Это первое событие в пользовательской команде loginAs, гарантирующее, что Cypress вышел из системы, прежде чем пытаться войти в систему как конкретный пользователь.

Используя переменные среды, вы даже можете создать команду Cypress с именем drush(), которую вы можете использовать для выполнения команд Drush в своих тестах или пользовательских командах. Посмотрите, как просто это позволяет определить пользовательскую команду Cypress, которая регистрирует пользователя, используя его UID:

/**
* Logs a user in by their uid via drush uli.
*/
 
Cypress.Commands.add('loginUserByUid', (uid) => {
 cy.drush('user-login', [], { uid, uri: Cypress.env('baseUrl') })
   .its('stdout')
   .then(function (url) {
     cy.visit(url);
   });
});

В этом примере используется drush user-loginкоманда ( drush uliдля краткости) и переводит аутентифицированного пользователя на базовый URL-адрес сайта.

Учитывайте преимущество безопасности, заключающееся в том, что вы никогда не читаете и не храните пароли пользователей при тестировании. Лично я нахожу удивительным, что интерфейсная технология, такая как Cypress, может выполнять команды Drush, которые я всегда считал очень важными для серверной части.

Тестирование, тестирование

В Cypress есть намного больше, например, фикстуры (файлы, содержащие тестовые данные) и различные приемы для навигации по иногда сложным структурам данных, которые создают пользовательский интерфейс веб-сайта. Чтобы узнать, что возможно, посмотрите веб-семинар Cypress Testing for Drupal Websites , особенно раздел о фикстурах, который начинается в 18:33 . На этом вебинаре более подробно рассматриваются некоторые интересные варианты использования, в том числе форма с поддержкой Ajax. Как только вы начнете использовать его, не стесняйтесь использовать или разветвлять публичный репозиторий Cypress Testing for Drupal от Aten .

Удачного тестирования!

Оригинальный источник статьи: https://opensource.com/

#cypress #test #drupal #website 

Как протестировать свой сайт на Drupal с помощью Cypress
木村  直子

木村 直子

1682570100

如何使用 Cypress 测试您的 Drupal 网站

测试让一切变得更好。了解如何将 Cypress 用于您的 Drupal 网站。

如果您不在 Drupal 开发中包含测试,很可能是因为您认为它增加了复杂性和费用而没有好处。Cypress是一种开源工具,具有许多优点:

  • 可靠地测试在网络浏览器中运行的任何东西
  • 适用于任何网络平台(非常适合使用React等前端技术测试项目)
  • 高度可扩展
  • 越来越受欢迎
  • 易于学习和实施
  • 随着您的项目变得更加复杂,防止回归
  • 可以让你的开发过程更有效率

本文涵盖三个主题,可帮助您开始使用 Cypress 测试您的 Drupal 项目:

  1. 安装赛普拉斯
  2. 使用 Cypress 编写和运行基本测试
  3. 为 Drupal 定制赛普拉斯

安装赛普拉斯

出于本教程的目的,我假设您已经使用 `drupal/recommended-project` 项目为您的 Drupal 项目构建了一个本地开发环境。虽然创建此类项目的详细信息超出了本文的范围,但我建议 使用 Lando 和 Drupal 9 入门

您的项目至少具有以下基本结构:

vendor/
web/
.editorconfig
.gitattributes
composer.json
composer.lock

cypress.io 站点有针对各种环境的完整安装说明。对于本文,我使用npm安装了 Cypress 。

使用命令初始化您的项目npm init。回答 Node.js 问你的问题,然后你会得到一个package.json看起来像这样的文件:

{
  "name": "cypress",
  "version": "1.0.0",
  "description": "Installs Cypress in a test project.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

在您的项目中安装 Cypress:

$ npm install cypress --save-dev

第一次运行 Cypress:

$ npx cypress open

由于您尚未向 Cypress 添加配置或任何脚手架文件,因此 Cypress 应用程序会显示欢迎屏幕以帮助您配置项目。要为 E2E(端到端)测试配置您的项目,请单击E2E 测试的未配置按钮。赛普拉斯将一些文件添加到您的项目中:

cypress/
node_modules/
vendor/ 
web/
.editorconfig
.gitattributes
composer.json
composer.lock
cypress.config.js
package-lock.json
package.json

单击继续并选择您喜欢的浏览器进行测试。单击[您选择的浏览器] 中的 Start E2E Testing。我在本文中使用基于 Chromium 的浏览器。

在一个单独的窗口中,浏览器打开到创建您的第一个规范页面:

网络浏览器中的赛普拉斯

(乔丹格雷厄姆,CC BY-SA 4.0)

单击Scaffold example specs按钮创建几个包含示例规范的新文件夹,以帮助您了解如何使用 Cypress。在您的代码编辑器中通读这些内容,您可能会发现该语言(基于 JavaScript)直观且易于理解。

单击测试浏览器中的任何一个。这揭示了两个面板。在左侧,文本面板显示了活动规范中的每个步骤。在右侧,一个模拟的浏览器窗口显示了赛普拉斯逐步执行规范时的实际用户体验。

打开cypress.config.js项目根目录中的文件并按如下方式更改它:

const { defineConfig } = require("cypress");
 
module.exports = defineConfig({
  component: {
    fixturesFolder: "cypress/fixtures",
    integrationFolder: "cypress/integration",
    pluginsFile: "cypress/plugins/index.js",
    screenshotsFolder: "cypress/screenshots",
    supportFile: "cypress/support/e2e.js",
    videosFolder: "cypress/videos",
    viewportWidth: 1440,
    viewportHeight: 900,
  },

  e2e: {
    setupNodeEvents(on, config) {
      // implement node event listeners here
    },
    baseUrl: "https://[your-local-dev-url]",
    specPattern: "cypress/**/*.{js,jsx,ts,tsx}",
    supportFile: "cypress/support/e2e.js",
    fixturesFolder: "cypress/fixtures"
   },
 });

在本地开发环境中将更改baseUrl为项目的 URL。

这些更改告诉赛普拉斯在哪里可以找到它的资源以及如何找到项目中的所有规范。

使用 Cypress 编写和运行基本测试

integration在您的目录中创建一个名为的新目录/cypress。在integration目录中,创建一个名为的文件test.cy.js

cypress/
├─ e2e/
├─ fixtures/
├─ integration/ 
│  ├─ test.cy.js
├─ support/ 
node_modules/
vendor/
web/
.editorconfig
.gitattributes
composer.json
composer.lock
cypress.config.js
package-lock.json
package.json

将以下内容添加到您的test.cy.js文件中:

describe('Loads the front page', () => {
  it('Loads the front page', () => {
    cy.visit('/')
    cy.get('h1.page-title')
      .should('exist')
  });
});
 
describe('Tests logging in using an incorrect password', () => {
  it('Fails authentication using incorrect login credentials', () => {
    cy.visit('/user/login')
    cy.get('#edit-name')
      .type('Sir Lancelot of Camelot')
    cy.get('#edit-pass')
      .type('tacos')
    cy.get('input#edit-submit')
      .contains('Log in')
      .click()
    cy.contains('Unrecognized username or password.')
  });
});

当您在 Cypress 应用程序中单击时,在 Cypress 执行每个部分test.cy.js中的步骤时,请注意左侧的每个测试描述。describe()

本规范演示了如何让 Cypress 导航您的网站、通过 ID 访问 HTML 元素、将内容输入到输入元素中以及提交表单。在这个过程中,我发现我需要添加断言,即元素<input id="edit-submit">包含文本Log in before input was clickable。显然,提交输入的灵活样式阻碍了赛普拉斯“看到”输入的能力,因此它无法点击它。测试确实有效!

为 Drupal 定制赛普拉斯

您也可以编写自己的自定义 Cypress 命令。还记得文件supportFile中的条目cypress.config.js吗?它指向赛普拉斯添加的文件,后者又导入文件./commands。顺便说一下,Cypress 非常聪明,在导入逻辑或数据夹具时,您不需要指定文件扩展名,所以您导入的是./commands,而不是./commands.js. 赛普拉斯寻找十几个流行的文件扩展名中的任何一个,并了解如何识别和解析它们中的每一个。

输入命令来commands.js定义它们:

/**
 * Logs out the user.
 */
 
Cypress.Commands.add('drupalLogout', () => {
  cy.visit('/user/logout');
})
 
/**
 * Basic user login command. Requires valid username and password.
 *
 * @param {string} username
 *   The username with which to log in.
 * @param {string} password
 *   The password for the user's account.
 */
 
Cypress.Commands.add('loginAs', (username, password) => {
  cy.drupalLogout();
  cy.visit('/user/login');
  cy.get('#edit-name')
    .type(username);
  cy.get('#edit-pass').type(password, {
    log: false,
  });
 
  cy.get('#edit-submit').contains('Log in').click();
});

此示例定义了一个名为 的自定义 Cypress 命令drupalLogout(),您可以在任何后续逻辑中使用它,甚至可以在其他自定义命令中使用它。要注销用户,请调用cy.drupalLogout()。这是自定义命令中的第一个事件,loginAs用于确保在尝试以特定用户身份登录之前注销 Cypress。

使用环境变量,您甚至可以创建一个名为 的 Cypress 命令drush(),您可以使用它在您的测试或自定义命令中执行 Drush 命令。看看这使得定义一个自定义 Cypress 命令来记录用户使用他们的 UID 是多么简单:

/**
* Logs a user in by their uid via drush uli.
*/
 
Cypress.Commands.add('loginUserByUid', (uid) => {
 cy.drush('user-login', [], { uid, uri: Cypress.env('baseUrl') })
   .its('stdout')
   .then(function (url) {
     cy.visit(url);
   });
});

此示例使用drush user-login命令(drush uli简称)并将经过身份验证的用户带到站点的基本 URL。

考虑在测试中从不读取或存储用户密码的安全优势。就个人而言,我觉得像 Cypress 这样的前端技术可以执行 Drush 命令真是太神奇了,我一直认为这在后端非常重要。

测试,测试

Cypress 还有很多其他功能,例如固定装置(保存测试数据的文件)和用于导航生成网站用户界面的有时复杂的数据结构的各种技巧。要了解可能性,请观看Cypress Testing for Drupal Websites网络研讨会,特别是 18:33 开始的关于固定装置的部分。该网络研讨会更详细地介绍了一些有趣的用例,包括支持 Ajax 的表单。一旦开始使用它,请随意使用或分叉Aten 的 Cypress Testing for Drupal 公共存储库

测试愉快!

文章原文出处:https: //opensource.com/

#cypress #test #drupal #website 

如何使用 Cypress 测试您的 Drupal 网站

How to Test for Undefined in JavaScript

An undefined variable or anything without a value will always return "undefined" in JavaScript. This is not the same as null, despite the fact that both imply an empty state.

You'll typically assign a value to a variable after you declare it, but this is not always the case.

When a variable is declared or initialized but no value is assigned to it, JavaScript automatically displays "undefined". It looks like this:

let myStr;

console.log(myStr); // undefined

Also, when you try accessing values in, for example, an array or object that doesn’t exist, it will throw undefined.

let user = {
    name: "John Doe",
    age: 14
};

console.log(user.hobby); // undefined

Here's another example:

let myArr = [12, 33, 44];

console.log(myArr[7]); // undefined

In this article, you will learn the various methods and approaches you can use to know if a variable is undefined in JavaScript. This is necessary if you want to avoid your code throwing errors when performing an operation with an undefined variable.

In case you are in a rush, here are the three standard methods that can help you check if a variable is undefined in JavaScript:

if(myStr === undefined){}
if(typeof myArr[7] === "undefined"){}
if(user.hobby === void 0){}

Let’s now explain each of these methods in more detail.

How to Check if a Variable is Undefined in JavaScript with Direct Comparison

One of the first methods that comes to mind is direct comparison. This is where you compare the output to see if it returns undefined. You can easily do this in the following way:

let user = {
    name: "John Doe",
    age: 14
};

if (user.hobby === undefined) {
    console.log("This is undefined");
}

This also works for arrays as you can see below:

let scores = [12, 34, 66, 78];

if (scores[10] === undefined) {
    console.log("This is undefined");
}

And it definitely also works for other variables:

let name;

if (name === undefined) {
    console.log("This is undefined");
}

How to Check if a Variable is Undefined in JavaScript with typeof

We can also use the type of the variable to check if it’s undefined. Luckily for us undefined is a datatype for an undefined value as you can see below: ‌

let name;

console.log(typeof name); // "undefined"

With this we can now use the datatype to check undefined for all types of data as we saw above. Here is what the check will look like for all three scenarios we have considered:

if(typeof user.hobby === "undefined"){}
if(typeof scores[10] === "undefined"){}
if(typeof name === "undefined"){}

How to Check if a Variable is Undefined in JavaScript with the Void Operator

The void operator is often used to obtain the undefined primitive value. You can do this using "void(0)" which is similar to "void 0" as you can see below:

console.log(void 0); // undefined
console.log(void(0)); // undefined

In the actual sense, this works like direct comparison (which we saw before). But we would replace undefined with void(0) or void 0 as seen below:

if(typeof user.hobby === void 0){}
if(typeof scores[10] === void 0){}
if(typeof name === void 0){}

Or like this:

if(typeof user.hobby === void(0)){}
if(typeof scores[10] === void(0)){}
if(typeof name === void(0)){}

Conclusion

In this article, we learned how to check if a variable is undefined and what causes a variable to be undefined.

We also learned three methods we can use to check if a variable is undefined. All methods work perfectly. Choosing your preferred method is totally up to you.

Have fun coding!

Original article source at: https://www.freecodecamp.org/

#javascript #test #undefined 

How to Test for Undefined in JavaScript

Как проверить неопределенность в JavaScript

Неопределенная переменная или что-то еще без значения всегда будет возвращать «неопределенное» в JavaScript. Это не то же самое, что null, несмотря на то, что оба они подразумевают пустое состояние.

Обычно вы присваиваете значение переменной после ее объявления, но это не всегда так.

Когда переменная объявлена ​​или инициализирована, но ей не присвоено значение, JavaScript автоматически отображает «undefined». Это выглядит так:

let myStr;

console.log(myStr); // undefined

Кроме того, когда вы пытаетесь получить доступ к значениям, например, в несуществующем массиве или объекте, он выдает undefined.

let user = {
    name: "John Doe",
    age: 14
};

console.log(user.hobby); // undefined

Вот еще один пример:

let myArr = [12, 33, 44];

console.log(myArr[7]); // undefined

В этой статье вы узнаете о различных методах и подходах, которые вы можете использовать, чтобы узнать, находится ли переменная undefinedв JavaScript. Это необходимо, если вы хотите, чтобы ваш код не выдавал ошибки при выполнении операции с неопределенной переменной.

Если вы спешите, вот три стандартных метода, которые помогут вам проверить, находится ли переменная undefinedв JavaScript:

if(myStr === undefined){}
if(typeof myArr[7] === "undefined"){}
if(user.hobby === void 0){}

Давайте теперь объясним каждый из этих методов более подробно.

Как проверить, не определена ли переменная в JavaScript с помощью прямого сравнения

Одним из первых методов, который приходит на ум, является прямое сравнение. Здесь вы сравниваете вывод, чтобы увидеть, возвращает ли он undefined. Вы можете легко сделать это следующим образом:

let user = {
    name: "John Doe",
    age: 14
};

if (user.hobby === undefined) {
    console.log("This is undefined");
}

Это также работает для массивов, как вы можете видеть ниже:

let scores = [12, 34, 66, 78];

if (scores[10] === undefined) {
    console.log("This is undefined");
}

И это определенно работает и для других переменных:

let name;

if (name === undefined) {
    console.log("This is undefined");
}

Как проверить, не определена ли переменная в JavaScript с помощьюtypeof

Мы также можем использовать тип переменной, чтобы проверить, является ли она undefined. К счастью для нас, undefined — это тип данных для неопределенного значения, как вы можете видеть ниже: ‌

let name;

console.log(typeof name); // "undefined"

Теперь мы можем использовать тип данных для проверки undefined для всех типов данных, как мы видели выше. Вот как будет выглядеть проверка для всех трех рассмотренных нами сценариев:

if(typeof user.hobby === "undefined"){}
if(typeof scores[10] === "undefined"){}
if(typeof name === "undefined"){}

Как проверить, не определена ли переменная в JavaScript с помощью Voidоператора

Оператор voidчасто используется для получения undefinedпримитивного значения. Вы можете сделать это, используя " void(0)", который похож на " void 0", как вы можете видеть ниже:

console.log(void 0); // undefined
console.log(void(0)); // undefined

На самом деле это работает как прямое сравнение (которое мы уже видели). Но мы бы заменили undefined на void(0)или, void 0как показано ниже:

if(typeof user.hobby === void 0){}
if(typeof scores[10] === void 0){}
if(typeof name === void 0){}

Или вот так:

if(typeof user.hobby === void(0)){}
if(typeof scores[10] === void(0)){}
if(typeof name === void(0)){}

Заключение

В этой статье мы узнали, как проверить, является ли переменная неопределенной, и что приводит к тому, что переменная не определена.

Мы также изучили три метода, которые можно использовать для проверки того, является ли переменная неопределенной. Все методы работают идеально. Выбор предпочтительного метода полностью зависит от вас.

Получайте удовольствие от кодирования!

Оригинальный источник статьи: https://www.freecodecamp.org/

#javascript #test #undefined 

Как проверить неопределенность в JavaScript
田辺  桃子

田辺 桃子

1681508520

如何在 JavaScript 中测试未定义

一个未定义的变量或任何没有值的东西在 JavaScript 中总是返回“undefined”。这与 null 不同,尽管两者都表示空状态。

您通常会在声明变量后为其赋值,但情况并非总是如此。

当一个变量被声明或初始化但没有赋值给它时,JavaScript 会自动显示“undefined”。它看起来像这样:

let myStr;

console.log(myStr); // undefined

此外,当您尝试访问不存在的数组或对象中的值时,它会抛出undefined.

let user = {
    name: "John Doe",
    age: 14
};

console.log(user.hobby); // undefined

这是另一个例子:

let myArr = [12, 33, 44];

console.log(myArr[7]); // undefined

在本文中,您将了解可用于了解变量是否在 JavaScript 中的各种方法undefined。如果您想避免代码在使用未定义变量执行操作时抛出错误,则这是必要的。

如果您赶时间,可以使用以下三种标准方法来帮助您检查变量是否在undefinedJavaScript 中:

if(myStr === undefined){}
if(typeof myArr[7] === "undefined"){}
if(user.hobby === void 0){}

现在让我们更详细地解释这些方法中的每一个。

如何通过直接比较检查 JavaScript 中的变量是否未定义

首先想到的方法之一是直接比较。这是您比较输出以查看它是否返回的地方undefined。您可以通过以下方式轻松执行此操作:

let user = {
    name: "John Doe",
    age: 14
};

if (user.hobby === undefined) {
    console.log("This is undefined");
}

这也适用于数组,如下所示:

let scores = [12, 34, 66, 78];

if (scores[10] === undefined) {
    console.log("This is undefined");
}

它肯定也适用于其他变量:

let name;

if (name === undefined) {
    console.log("This is undefined");
}

如何在 JavaScript 中检查变量是否未定义typeof

我们还可以使用变量的类型来检查它是否是undefined. 对我们来说幸运的是 undefined 是一个未定义值的数据类型,如下所示:

let name;

console.log(typeof name); // "undefined"

有了这个,我们现在可以使用数据类型来检查所有类型数据的未定义,就像我们上面看到的那样。以下是我们考虑过的所有三种情况的检查结果:

if(typeof user.hobby === "undefined"){}
if(typeof scores[10] === "undefined"){}
if(typeof name === "undefined"){}

如何使用运算符在 JavaScript 中检查变量是否未定义Void

运算void符常用于获取undefined原始值。您可以使用void(0)类似于“ ”的“ void 0”来执行此操作,如下所示:

console.log(void 0); // undefined
console.log(void(0)); // undefined

在实际意义上,这就像直接比较(我们之前看到的)。但是我们会用void(0)or替换 undefined ,void 0如下所示:

if(typeof user.hobby === void 0){}
if(typeof scores[10] === void 0){}
if(typeof name === void 0){}

或者像这样:

if(typeof user.hobby === void(0)){}
if(typeof scores[10] === void(0)){}
if(typeof name === void(0)){}

结论

在本文中,我们学习了如何检查变量是否未定义以及导致变量未定义的原因。

我们还学习了三种可用于检查变量是否未定义的方法。所有方法都非常有效。选择您喜欢的方法完全取决于您。

享受编码乐趣!

文章原文出处:https: //www.freecodecamp.org/

#javascript #test #undefined 

如何在 JavaScript 中测试未定义

How to Test for Undefined in JavaScript

An undefined variable or anything without a value will always return "undefined" in JavaScript. This is not the same as null, despite the fact that both imply an empty state.

You'll typically assign a value to a variable after you declare it, but this is not always the case.

When a variable is declared or initialized but no value is assigned to it, JavaScript automatically displays "undefined". It looks like this:

let myStr;

console.log(myStr); // undefined

Also, when you try accessing values in, for example, an array or object that doesn’t exist, it will throw undefined.

let user = {
    name: "John Doe",
    age: 14
};

console.log(user.hobby); // undefined

Here's another example:

let myArr = [12, 33, 44];

console.log(myArr[7]); // undefined

In this article, you will learn the various methods and approaches you can use to know if a variable is undefined in JavaScript. This is necessary if you want to avoid your code throwing errors when performing an operation with an undefined variable.

In case you are in a rush, here are the three standard methods that can help you check if a variable is undefined in JavaScript:

if(myStr === undefined){}
if(typeof myArr[7] === "undefined"){}
if(user.hobby === void 0){}

Let’s now explain each of these methods in more detail.

How to Check if a Variable is Undefined in JavaScript with Direct Comparison

One of the first methods that comes to mind is direct comparison. This is where you compare the output to see if it returns undefined. You can easily do this in the following way:

let user = {
    name: "John Doe",
    age: 14
};

if (user.hobby === undefined) {
    console.log("This is undefined");
}

This also works for arrays as you can see below:

let scores = [12, 34, 66, 78];

if (scores[10] === undefined) {
    console.log("This is undefined");
}

And it definitely also works for other variables:

let name;

if (name === undefined) {
    console.log("This is undefined");
}

How to Check if a Variable is Undefined in JavaScript with typeof

We can also use the type of the variable to check if it’s undefined. Luckily for us undefined is a datatype for an undefined value as you can see below: ‌

let name;

console.log(typeof name); // "undefined"

With this we can now use the datatype to check undefined for all types of data as we saw above. Here is what the check will look like for all three scenarios we have considered:

if(typeof user.hobby === "undefined"){}
if(typeof scores[10] === "undefined"){}
if(typeof name === "undefined"){}

How to Check if a Variable is Undefined in JavaScript with the Void Operator

The void operator is often used to obtain the undefined primitive value. You can do this using "void(0)" which is similar to "void 0" as you can see below:

console.log(void 0); // undefined
console.log(void(0)); // undefined

In the actual sense, this works like direct comparison (which we saw before). But we would replace undefined with void(0) or void 0 as seen below:

if(typeof user.hobby === void 0){}
if(typeof scores[10] === void 0){}
if(typeof name === void 0){}

Or like this:

if(typeof user.hobby === void(0)){}
if(typeof scores[10] === void(0)){}
if(typeof name === void(0)){}

Conclusion

In this article, we learned how to check if a variable is undefined and what causes a variable to be undefined.

We also learned three methods we can use to check if a variable is undefined. All methods work perfectly. Choosing your preferred method is totally up to you.

Have fun coding!

Original article source at: https://www.freecodecamp.org/

#javascript #test #undefined 

How to Test for Undefined in JavaScript

Planning To Take Certified Ethical Hacker (CEH)?

CEH-Exam-Questions

Planning To Take Certified Ethical Hacker (CEH)? Here are github repo with 125 questions and answers to help you prep for the test

A Certified Ethical Hacker(CEH) is a skilled professional who understands and knows how to look for weaknesses and vulnerabilities in target systems and uses the same knowledge and tools as a malicious hacker, but in a lawful and legitimate manner to assess the security posture of a target system(s). The CEH credential certifies individuals in the specific network security discipline of Ethical Hacking from a vendor-neutral perspective.

About the Exam -
 

  1. Number of Questions: 125 Only
     
  2. Test Duration: 4 Hours
     
  3. Test Format: Multiple Choice Questions
     
  4. Test Delivery: ECC EXAM, VUE
     
  5. Exam Prefix: 312-50 (ECC EXAM), 312-50 (VUE)
     

Chapter 0 - Assessment Test (35)
Chapter 1 - Introduction (20)
Chapter 2 - System Fundamentals (20)
Chapter 3 - Cryptography (20)
Chapter 4 - Footprinting (20)
Chapter 5 - Scanning (20)
Chapter 6 - Enumeration (20)
Chapter 7 - System Hacking (20)
Chapter 8 - Malware (20)
Chapter 9 - Sniffers (20)
Chapter 10 - Social Engineering (20)
Chapter 11 - Denial of Service (20)
Chapter 12 - Session Hijacking (20)
Chapter 13 - Web Servers & Applications (20)
Chapter 14 - SQL Injection (20)
Chapter 15 - Hacking Wi-Fi & Bluetooth (20)
Chapter 16 - Mobile Device Security (20)
Chapter 17 - Evasion (20)
Chapter 18 - Cloud Technologies & Security (20)
Chapter 19 - Physical Security (20)


Download Details:

Author: ryh04x
Source Code: https://github.com/ryh04x/CEH-Exam-Questions 

#github #questions #answers #test 

Planning To Take Certified Ethical Hacker (CEH)?
Monty  Boehm

Monty Boehm

1678871100

Podinfo: Go Microservice Template for Kubernetes

Podinfo

Podinfo is a tiny web application made with Go that showcases best practices of running microservices in Kubernetes. Podinfo is used by CNCF projects like Flux and Flagger for end-to-end testing and workshops.

Specifications:

  • Health checks (readiness and liveness)
  • Graceful shutdown on interrupt signals
  • File watcher for secrets and configmaps
  • Instrumented with Prometheus and Open Telemetry
  • Structured logging with zap
  • 12-factor app with viper
  • Fault injection (random errors and latency)
  • Swagger docs
  • CUE, Helm and Kustomize installers
  • End-to-End testing with Kubernetes Kind and Helm
  • Multi-arch container image with Docker buildx and Github Actions
  • Container image signing with Sigstore cosign
  • SBOMs and SLSA Provenance embedded in the container image
  • CVE scanning with Trivy

Web API:

  • GET / prints runtime information
  • GET /version prints podinfo version and git commit hash
  • GET /metrics return HTTP requests duration and Go runtime metrics
  • GET /healthz used by Kubernetes liveness probe
  • GET /readyz used by Kubernetes readiness probe
  • POST /readyz/enable signals the Kubernetes LB that this instance is ready to receive traffic
  • POST /readyz/disable signals the Kubernetes LB to stop sending requests to this instance
  • GET /status/{code} returns the status code
  • GET /panic crashes the process with exit code 255
  • POST /echo forwards the call to the backend service and echos the posted content
  • GET /env returns the environment variables as a JSON array
  • GET /headers returns a JSON with the request HTTP headers
  • GET /delay/{seconds} waits for the specified period
  • POST /token issues a JWT token valid for one minute JWT=$(curl -sd 'anon' podinfo:9898/token | jq -r .token)
  • GET /token/validate validates the JWT token curl -H "Authorization: Bearer $JWT" podinfo:9898/token/validate
  • GET /configs returns a JSON with configmaps and/or secrets mounted in the config volume
  • POST/PUT /cache/{key} saves the posted content to Redis
  • GET /cache/{key} returns the content from Redis if the key exists
  • DELETE /cache/{key} deletes the key from Redis if exists
  • POST /store writes the posted content to disk at /data/hash and returns the SHA1 hash of the content
  • GET /store/{hash} returns the content of the file /data/hash if exists
  • GET /ws/echo echos content via websockets podcli ws ws://localhost:9898/ws/echo
  • GET /chunked/{seconds} uses transfer-encoding type chunked to give a partial response and then waits for the specified period
  • GET /swagger.json returns the API Swagger docs, used for Linkerd service profiling and Gloo routes discovery

gRPC API:

  • /grpc.health.v1.Health/Check health checking

Web UI:

podinfo-ui

To access the Swagger UI open <podinfo-host>/swagger/index.html in a browser.

Guides

Install

To install Podinfo on Kubernetes the minimum required version is Kubernetes v1.23.

Helm

Install from github.io:

helm repo add podinfo https://stefanprodan.github.io/podinfo

helm upgrade --install --wait frontend \
--namespace test \
--set replicaCount=2 \
--set backend=http://backend-podinfo:9898/echo \
podinfo/podinfo

helm test frontend --namespace test

helm upgrade --install --wait backend \
--namespace test \
--set redis.enabled=true \
podinfo/podinfo

Install from ghcr.io:

helm upgrade --install --wait podinfo --namespace default \
oci://ghcr.io/stefanprodan/charts/podinfo

Kustomize

kubectl apply -k github.com/stefanprodan/podinfo//kustomize

Docker

docker run -dp 9898:9898 stefanprodan/podinfo

Continuous Delivery

In order to install podinfo on a Kubernetes cluster and keep it up to date with the latest release in an automated manner, you can use Flux.

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Install the Flux controllers needed for Helm operations:

flux install \
--namespace=flux-system \
--network-policy=false \
--components=source-controller,helm-controller

Add podinfo's Helm repository to your cluster and configure Flux to check for new chart releases every ten minutes:

flux create source helm podinfo \
--namespace=default \
--url=https://stefanprodan.github.io/podinfo \
--interval=10m

Create a podinfo-values.yaml file locally:

cat > podinfo-values.yaml <<EOL
replicaCount: 2
resources:
  limits:
    memory: 256Mi
  requests:
    cpu: 100m
    memory: 64Mi
EOL

Create a Helm release for deploying podinfo in the default namespace:

flux create helmrelease podinfo \
--namespace=default \
--source=HelmRepository/podinfo \
--release-name=podinfo \
--chart=podinfo \
--chart-version=">5.0.0" \
--values=podinfo-values.yaml

Based on the above definition, Flux will upgrade the release automatically when a new version of podinfo is released. If the upgrade fails, Flux can rollback to the previous working version.

You can check what version is currently deployed with:

flux get helmreleases -n default

To delete podinfo's Helm repository and release from your cluster run:

flux -n default delete source helm podinfo
flux -n default delete helmrelease podinfo

If you wish to manage the lifecycle of your applications in a GitOps manner, check out this workflow example for multi-env deployments with Flux, Kustomize and Helm.


Download Details:

Author: Stefanprodan
Source Code: https://github.com/stefanprodan/podinfo 
License: Apache-2.0 license

#kubernetes #golang #microservice #helm #test #gitops 

Podinfo: Go Microservice Template for Kubernetes

Amit Patel

1678169051

Ruby 3.0: Faster Than Before

The basic principle of ruby 3 is to keep compatibility and make the language faster and more productive. Thus, the main three aspects of the new version are making ruby fast, concurrent, and correct.

Faster Ruby:

The speed is achieved by improving the performance of MJIT. As a result, ruby runs three times faster than previous versions in some benchmarks, though not with the rails applications.

Concurrent Ruby:

In this multi-core age, concurrency is gained with Async I/O Fiber and Ractor.

  • Async I/O Fiber: A fiber for heavy I/O tasks. This doesn’t utilize the multi-core but utilizes blocking time to improve the performance of I/O tasks. This fiber is based on the technology used by the Ruby application server - Falcon.
  • Ractor: It stands for Ruby Actor which helps in improving CPU intensive tasks. There are isolated object spaces for each ractor and they communicate via channels that enable parallel execution without safety concerns. You can make multiple ractors and you can run them in parallel. Ractor enables you to make thread-safe parallel programs because ractors can not share normal objects. Communication between ractors is supported by exchanging messages. 

Correct Ruby:

Ruby seeks the future with static type checking, without type declaration, using abstract interpretation. RBS & Type Profiler are the first step in the future.

  • RBS (Ruby Signature):  It is a language similar to Ruby, but specially designed to describe types. Ruby 3 ships with RBS for the core library (RBS string, RBS hash, and so on). We can use this type of information in RBS files for type checking and better IDE with better code compilation.

Example:

class Test
 def test: () ->void   #test() returns nothing
 def to_s:() -> String
         |(Integer) -> String   #to_s() takes null or integer as an argument and returns string
end

  • Type Profiler: It does naive type checks, also generates RBS for your application using abstract interpretation. If you have some type of mismatch in your application, the type profiler will warn you about these errors.

Example:

class Test
  def test(a)
    b = a+2
    return b
  end
end
Test.new.test(15)

How does it work?

  1. The first type profiler will check the new instance of Test which calls test().
  2. Now, test() is bound to value 15 which is an integer.
  3. So, it can be said that a is an integer, meaning the test method takes integer input.
  4. Now, a has an addition (+) operation with 2 (again integer) which will return an integer. So, b is an integer.
  5. Lastly, it can be concluded that test() returns an integer.

RBS file for Test:

class Test
  def test: (Integer) -> Integer   #test passes int as an argument and returns int.
end

What's new:

  • ' => '  symbol is added which can be used as rightward assignment operator(right assignment)

>>  1 => a
>> puts a    #prints 1

  • Now ‘in’ returns true or false

>> O in 1   #returns false in the latest version, earlier it was giving an error.

  • The inline method definition is added.

>> def square (n) = n*n

  • except() function is added for hash

>> h = {a:1, b:2, c:3}
>> puts h.except(:a)  #prints {:b => 2, :c => 3}

 

Note: This Post Was First Published on https://essencesolusoft.com/blog/faster-ruby-3

Ruby 3.0: Faster Than Before
Nat  Grady

Nat Grady

1677834300

Carton: Watcher, Bundler, and Test Runner for Your SwiftWasm Apps

Carton 📦

Watcher, bundler, and test runner for your SwiftWasm apps

The main goal of carton is to provide a smooth zero-config experience when developing for WebAssembly. It currently supports these features with separate commands:

  • Creating basic package boilerplate for apps built with SwiftWasm with carton init.
  • Watching the app for source code changes and reloading it in your browser with carton dev.
  • Running your XCTest suite in the full JavaScript/DOM environment with carton test.
  • Optimizing and packaging the app for distribution with carton bundle.
  • Managing SwiftWasm toolchain and SDK installations with carton sdk.

Motivation

The main motivation for carton came after having enough struggles with webpack.js, trying to make its config file work, looking for appropriate plugins. At some point the maintainers became convinced that the required use of webpack in SwiftWasm projects could limit the wider adoption of SwiftWasm itself. Hopefully, with carton you can avoid using webpack altogether. carton also simplifies a few other things in your SwiftWasm development workflow such as toolchain and SDK installations.

Getting started

Requirements

  • macOS 11 and Xcode 13.2.1 or later. macOS 10.15 may work, but is untested.
  • Swift 5.5 or later and Ubuntu 18.04 or 20.04 for Linux users.

Installation

On macOS carton can be installed with Homebrew. Make sure you have Homebrew installed and then run:

brew install swiftwasm/tap/carton

Note If you can't install the latest carton via brew upgrade swiftwasm/tap/carton, please try rm -rf $(brew --prefix)/Library/Taps/swiftwasm/homebrew-tap/ && brew tap swiftwasm/tap and retry again. The master branch was renamed to main, so you need to update your local tap repo.

carton is also available as a Docker image for Linux. You can pull it with this command:

docker pull ghcr.io/swiftwasm/carton:latest

If Docker images are not suitable for you, you'll have to build carton from sources on Ubuntu. Clone the repository and run ./install_ubuntu_deps.sh in the root directory of the clone. After that completes successfully, run swift build -c release, the carton binary will be located in the .build/release directory after that. Unfortunately, other Linux distributions are currently not supported.

Version compatibility

carton previously embedded runtime parts of the JavaScriptKit library. This runtime allows Swift and JavaScript code to interoperate in Node.js and browser environments. Because of how JavaScriptKit runtime was embedded, older versions of JavaScriptKit were incompatible with different versions of carton and vice versa. This incompatibility between different versions was resolved starting with JavaScriptKit 0.15 and carton 0.15. All version combinations of carton and JavaScriptKit higher than those are compatible with each other.

You still have to keep in mind that older versions of SwiftWasm may be incompatible with newer carton. You can follow the compatibility matrix if you need to use older verions:

carton versionSwiftWasm versionJavaScriptKit versionTokamak version
0.15+5.60.15+0.10.1+
0.145.60.140.10
0.135.50.130.9.1
0.12.25.50.120.9.1
0.12.05.50.110.9.0
0.11.05.40.10.10.8.0

Usage

The carton init command initializes a new SwiftWasm project for you (similarly to swift package init) with multiple templates available at your choice. carton init --template tokamak creates a new Tokamak project, while carton init --template basic (equivalent to carton init) creates an empty SwiftWasm project with no dependencies. Also, carton init list-templates provides a complete list of templates (with only basic and tokamak available currently).

The carton dev command builds your project with the SwiftWasm toolchain and starts an HTTP server that hosts your WebAssembly executable and a corresponding JavaScript entrypoint that loads it. The app, reachable at http://127.0.0.1:8080/, will automatically open in your default web browser. The port that the development server uses can also be controlled with the --port option (or -p for short). You can edit the app source code in your favorite editor and save it, carton will immediately rebuild the app and reload all browser tabs that have the app open. You can also pass a --verbose flag to keep the build process output available, otherwise stale output is cleaned up from your terminal screen by default. If you have a custom index.html page you'd like to use when serving, pass a path to it with a --custom-index-page option.

The carton test command runs your test suite in wasmer, node or using your default browser. You can switch between these with the --environment option, passing either: wasmer, node or defaultBrowser. Code that depends on JavaScriptKit should pass either --environment node or --environment defaultBrowser options, depending on whether it needs Web APIs to work. Otherwise the test run will not succeed, since JavaScript environment is not available with --environment wasmer. If you want to run your test suite on CI or without GUI but on browser, you can pass --headless flag. It enables WebDriver-based headless browser testing. Note that you need to install a WebDriver executable in PATH before running tests. You can use the command with a prebuilt test bundle binary instead of building it in carton by passing --prebuilt-test-bundle-path <your binary path>.

The carton sdk command and its subcommands allow you to manage installed SwiftWasm toolchains, but is rarely needed, as carton dev installs the recommended version of SwiftWasm automatically. carton sdk versions lists all installed versions, and carton sdk local prints the version specified for the current project in the .swift-version file. You can however install SwiftWasm separately if needed, either by passing an archive URL to carton sdk install directly, or just specifying the snapshot version, like carton sdk install wasm-5.3-SNAPSHOT-2020-09-25-a.

carton dev can also detect existing installations of swiftenv, so if you already have SwiftWasm installed via swiftenv, you don't have to do anything on top of that to start using carton.

The carton bundle command builds your project using the release configuration (although you can pass the --debug flag to it to change that), and copies all required assets to the Bundle directory. You can then use a static file hosting (e.g. GitHub Pages) or any other server with support for static files to deploy your application. All resulting bundle files except index.html are named by their content hashes to enable cache busting. As with carton dev, a custom index.html page can be provided through the --custom-index-page option. You can also pass --debug-info flag to preserve names and DWARF sections in the resulting .wasm file, as these are stripped in the release configuration by default. By default, carton bundle will run wasm-opt on the resulting .wasm binary in order to reduce its file size. That behaviour can be disabled (in order to speed up the build) by appending the --wasm-optimizations none option.

The carton package command proxies its subcommands to swift package invocations on the currently-installed toolchain. This may be useful in situations where you'd like to generate an Xcode project file for your app with something like carton package generate-xcodeproj. It would be equivalent to swift package generate-xcodeproj, but invoked with the SwiftWasm toolchain instead of the toolchain supplied by Xcode.

All commands that delegate to swift build and swiftc (namely, dev, test, and bundle) can be passed -Xswiftc arguments, which is equivalent to -Xswiftc in swift build. All -Xswiftc arguments are propagated to swiftc itself unmodified.

All of these commands and subcommands can be passed a --help flag that prints usage info and information about all available options.

How does it work?

carton bundles a WASI polyfill, which is currently required to run any SwiftWasm code, and the JavaScriptKit runtime for convenience. carton also embeds an HTTP server for previewing your SwiftWasm app directly in a browser. The development version of the polyfill establishes a helper WebSocket connection to the server, so that it can reload development browser tabs when rebuilt binary is available. This brings the development experience closer to Xcode live previews, which you may have previously used when developing SwiftUI apps.

carton does not require any config files for these basic development scenarios, while some configuration may be supported in the future, for example for complex asset pipelines if needed. The only requirement is that your Package.swift contains at least a single executable product, which then will be compiled for WebAssembly and served when you start carton dev in the directory where Package.swift is located.

carton is built with Vapor, SwiftNIO, swift-tools-support-core, and supports both macOS and Linux. (Many thanks to everyone supporting and maintaining those projects!)

Running carton dev with the release configuration

By default carton dev will compile in the debug configuration. Add the --release flag to compile in the release configuration.

Contributing

Sponsorship

If this tool saved you any amount of time or money, please consider sponsoring the SwiftWasm organization. Or you can sponsor some of our maintainers directly on their personal sponsorship pages: @carson-katri, @kateinoigakukun, and @MaxDesiatov. While some of the sponsorship tiers give you priority support or even consulting time, any amount is appreciated and helps in maintaining the project.

Coding Style

This project uses SwiftFormat and SwiftLint to enforce formatting and coding style. We encourage you to run SwiftFormat within a local clone of the repository in whatever way works best for you either manually or automatically via an Xcode extension, build phase or git pre-commit hook etc.

To guarantee that these tools run before you commit your changes on macOS, you're encouraged to run this once to set up the pre-commit hook:

brew bundle # installs SwiftLint, SwiftFormat and pre-commit
pre-commit install # installs pre-commit hook to run checks before you commit

Refer to the pre-commit documentation page for more details and installation instructions for other platforms.

SwiftFormat and SwiftLint also run on CI for every PR and thus a CI build can fail with incosistent formatting or style. We require CI builds to pass for all PRs before merging.

Code of Conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to hello@swiftwasm.org.


Download Details:

Author: swiftwasm
Source Code: https://github.com/swiftwasm/carton 
License: Apache-2.0 license

#swift #webpack #test 

Carton: Watcher, Bundler, and Test Runner for Your SwiftWasm Apps
Nat  Grady

Nat Grady

1677786660

PSPautotests: A Test Suite Based on The Pspautotests SVN

PSPautotests

A repository of PSP programs performing several tests on the PSP platform.

  • It will allow people to see how to use some obscure-newly-discovered APIs and features
  • It will allow PSP emulators to avoid some regressions while performing refactorings and to have a reference while implementing APIs

The main idea behind this is having several files per test unit:

  • file.expected - File with the expected Kprintf's output, preferably from a real PSP
  • file.prx - The program that will call Kprintf syscall in order to generate an output
  • file.input - Optional file specifying automated actions that should simulate user interaction: pressing a key, releasing a key, selecting a file on the save selector, waiting for a function (for example a vsync) to call before continuing...

How to build and use

If you just want to run the tests, you just need to run your emulator on the PRX files and compare with the .expected files. PPSSPP has a convenient script for this called test.py.

If you want to change tests, you'll need to read the rest. This tutorial is focused on Windows but can probably be used on Linux and Mac too, you just don't need to install the driver there.

Prerequisites

The rest of this tutorial will assume that you installed the PSPSDK in C:\pspsdk.

Step 1: Install PSPLink on your PSP

  • Copy the OE version of PSPLink (C:\pspsdk\psplink\psp\oe\psplink) to PSP/GAME on the PSP.
  • Run it on your PSP from the game menu.

Step 2: Prepare the PC

Tip: If you see PSP Type A, you've connected the PSP in "USB mode". Disconnect, and run the PSPLINK game instead.

Windows 7 and later

  • Plug the PSP into your PC via USB while PSPLINK is running.
  • Use Zadig to install the libusb-win32 driver.
  • Make sure it says PSP Type B in Zadig and click Install Driver.

Windows XP / Vista / etc.

  • If you are on Vista x64, you may need to press F8 during boot up and select "Disable driver signing verification". You'll have to do this each boot on Vista x64.
  • After boot, plug the PSP into your PC via USB while PSPLINK is running.
  • Go into Device Manager and select the PSP Type B device in the list.
  • Right click on "PSP Type B" -> Properties.
  • Select Update Driver and select "I have my own driver".
  • For the path, use C:\pspsdk\bin\driver or C:\pspsdk\bin\driver_x64 depending on your OS install.

Mac OS X

Linux

Step 3: Add pspsdk to PATH

  • Add C:\pspsdk\bin (or equivalent) to your PATH if you haven't already got it.
  • Go to pspautotests\common and run make (might need to start a new cmd shell)

You are now ready to roll!

Running tests

In a command prompt in the directory that you want the PSP software to regard as "host0:/" (normally pspautotests/) if it tries to read files over the cable, type the following:

> cd pspautotests
> usbhostfs_pc -b 3000

Then in a separate command prompt:

> pspsh -p 3000

If you now don't see a host0:/ prompt, something is wrong. Most likely the driver has not loaded correctly. If the port 3000 happened to be taken (usbhostfs_pc would have complained), try another port number.

Now you have full access to the PSP from this prompt.

You can exit it and use gentest.py (which will start the same prompt) to run tests (e.g. gentest.py misc/testgp) and update the .expected files.

You can run executables on the PSP that reside on the PC directly from within this the pspsh shell, just cd to the directory and run ./my_program.prx.

Note that you CAN'T run ELF files on modern firmware, you MUST build as .PRX. To do this, set BUILD_PRX = 1 in your makefile.

Also, somewhere in your program, add the following line to get a proper heap size:

unsigned int sce_newlib_heap_kb_size = -1;

For some probably historical reason, by default PSPSDK assumes that you want a 64k heap when you build a PRX.

TODO

Maybe join .expected and .input file in a single .test file?

Random Ideas for .test file:

EXPECTED:CALL(sceDisplay.sceDisplayWaitVblank)
ACTION:BUTTON_PRESS(CROSS)
EXPECTED:OUTPUT('CROSS Pressed')
EXPECTED:CALL(sceDisplay.sceDisplayWaitVblank)
ACTION:BUTTON_RELEASE(CROSS)


Download Details:

Author: Hrydgard
Source Code: https://github.com/hrydgard/pspautotests 
License: View license

#cpluplus #test #based 

PSPautotests: A Test Suite Based on The Pspautotests SVN
Desmond  Gerber

Desmond Gerber

1677744420

How to Test Driven Development for Java using JUnit

How to Test Driven Development for Java using JUnit

Introduction

Before we get started, let us understand some basics. Software testing plays an important role in the life cycle of software development. It is imperative to identify bugs and errors during software development and increase the quality of the product. Additionally we need software testing to ensure that the software fulfils the client specifications, responds correctly to inputs (input validation), runs in a reasonable time (performance testing), is easy to install and run (deployment testing), and meets the stakeholders' goals.

Therefore, one must focus on software testing. There are many approaches and TDD approach is one of them. It is a key practice for extreme programming, it suggests that the code is developed or changed exclusively based on the Unit Testing.

What is Test Driven Development?

TDD is a software development process which includes test-first development. It means that the developer first writes a fully automated test case before writing the production code to fulfil that test and refactoring. Steps for the same are given below -

  1. Firstly, add a test.
  2. Run all the tests and see if any new test fails.
  3. Update the code to make it pass the new tests.
  4. Run the test again and if they fail then refactor again and repeat.

What is Behaviour Driven Development (BDD)?

It is similar to Test Driven Development. In other words, BDD is the extended version of TDD. The process is similar to it. In this also, the code is first written in Behaviour Driven Development and the production code. But, the main difference is that in Behaviour Driven Development the test is written in plain descriptive English type grammar as opposed to TDD. This type of development -

  • Explained the behaviour of the software/program.
  • User friendly

The major benefit of it is that it can easily be understood by a non-technical person also.

What is a Legacy Code?

In simple words, a code without testing is known as legacy code. A big disadvantage of legacy code is that it’s not easily understandable (for both developments as well as the business team) and that is the only reason why it is difficult to change the code for new features. Therefore, a code without tests is bad code. It is necessary to write code with tests for best productivity and easy modifications.

What are the advantages?

  1. It gives a way to think through our requirements or design before we write our functional code.
  2. Enables us to take small steps during building software.
  3. Makes us more productive in nature rather as compared attempting to code in large steps.

Let's take an example, assume that you write some code and then compile it and then test it and maybe there are chances of failure. In this case, it becomes easy to find and fix those defects if you've written two new lines of code than a thousand. Basically, a TDD is -

  • The most efficient and attractive way to proceed in smaller and smaller steps.
  • Following TDD means -
    • Fewer bugs
    • Higher quality software
    • Focus on single functionality at a given point in time

Why is Test Driven Development Important?

  • Requirements - Drive out requirement issues early (more focus on requirements in depth).
  • Rapid Feedback - Many small changes Vs One big change.
  • Values Refactoring - Refactor often to lower impact and risk.
  • Design to Test - Testing driving good design practice.
  • Tests as information - Documenting decisions and assumptions.

Why We Use Test Driven Development


Test Driven Development with Java

In the Java community, it plays an important role in designing and implementation of a software/program. Test-Driven Development helps the programmer in several ways, such as -

  • Improving the code
  • Side by side, increasing the programmer’s productivity.

Using Test-Driven Development concept in our programming skills -

  • Will save our time which is getting wasted for rework.
  • Able to identify the error/problem quicker and faster.
  • The programmer will be able to write small classes which will be focused only on a single functionality instead of writing the big classes.

The major problem with programmers is that, while programming whenever the code base gets bigger it becomes very difficult to change and debug the code because there is a high chance of the code getting messed up. But, if we are using Test Driven Development technique -

  • Means we have automated tests
  • We are writing the test cases for our program which is a safe side for the programmers.

It becomes easy to view what the error is, where it is and how it is paralyzing our code.

API Testing in TDD

API Testing is one of the types of testing techniques. This type of technique is used in the following cases -

  • Testing APIs (Application Programming Interfaces)
  • To determine if the API created meets the expectations.
  • End-to-end functionality (how an API technically works).
  • Response time.
  • Load Testing
  • Only API functions are tested.

During API testing if the API returns a valid/correct response, then that API will say to have passed. The outputs of an API testing are of three types -

  1. The output can contain status.
  2. The output can contain any type of data or information.
  3. Or an API can be calling another API.

API Testing can be done by -

  • Unit testing (testing the API methods and checking if the output meets the expectations).
  • Using many tools for checking the performance and load i.e how many requests can be handled by the API at the same time and many more. We can use Apache JMeter for performance and load testing.

What are the best Test-Driven Development Tools for java?

As discussed above, there are many tools available for testing and improving the overall design and implementation of the software system. Some of the most common testing tools are listed below -

JUnit for Unit Tests 

JUnit For Unit Testing

JUnit is a unit testing framework designed for Java programming language. Since unit tests are the smallest elements in the test automation process. With the help of unit tests, we can check the business logic of any class. So JUnit plays an important role in the development of a test driven development framework. It is one of the families of unit testing frameworks which is collectively known as the xUnit that originated with SUnit.

JMeter for Load/Performance Testing

JMeter For Load and Performance Testing

Apache JMeter may be used to test performance both on static and dynamic resources, Web dynamic applications (Mainly for Load/Performance testing). Basically, it is used to simulate a heavy load on a server, group of servers, network or object to test its strength or to analyze overall performance under different load types.

Features of Apache JMeter -

Ability to load and performs tests on many different applications/server/protocol types, some of them are listed below -

  1. Web - HTTP, HTTPS (Java, NodeJS, PHP, ASP.NET, …)
  2. SOAP/REST Webservices
  3. FTP
  4. Database via JDBC
  5. LDAP
  6. Message-oriented middleware (MOM) via JMS
  7. Mail - SMTP(S), POP3(S) and IMAP(S)
  8. Native commands or shell scripts
  9. TCP
  10. Java Objects

Mockito for Rest API Testing

Mockito For REST API Testing

Mockito is designed as an open-source testing framework for Java which is available under an MIT License. It allows programmers to create and test double objects (mock objects) in automated unit tests for the purpose of TDD. In simple words, we can say that Mockito is a framework that we specifically use to efficiently write certain kind of tests.


How to set up environment for Test Driven Development in Java?

The steps to set up environment for TDD in Java are listed below:

Setting up it with JUnit

  • Install Java first.
  • Then we need Eclipse or any other IDE(Integrated Development Environment).
  • Create a new project (Maven project) and place the JUnit maven dependency in pom.xml file.

OR If it’s not a Maven project then download the JUnit jar and include it in your project.

Setting up it with JMeter

  • Install Java.
  • Install Apache JMeter
    • For Ubuntu - $ Sudo apt-get install JMeter
    • For CentOS7 - Sudo yum install JMeter

Setting Up TDD with Mockito

  • Install Java.
  • Then we need Eclipse or any other IDE(Integrated Development Environment).
  • Create a new project and download the mockito jar and include it in the project and if it is a maven project then add mockito dependency in pom.xml file for that particular project.

How to implementing Java Test Driven Development?

The steps to implement Java TDD are described below:

Naming the test class

We use common conventions in naming the test class. Let’s start with the name of the class which is being tested and assume the name of that class is “Student”. In that case, the name of the test class should be “StudentTest”. We have to append “Test” to it. The same naming convention is used in the case of methods. If there is a method “DisplayStudentAddress()”, then the name of the method in testing should be “testDisplayStudentAddress()”.

Naming in Production

Naming in Testing

Student

StudentTest

DisplayStudentAddress()

testDisplayStudentAddress()

Packages for production code

We don’t use the same package for production code and testing code. The best practice is to use different source directories, “src/main/java” for production and “src/test/java” for testing. 3. Structure and Annotation - @Test annotation (JUnit4/5) tells JUnit to execute the testDisplayStudentAddress() method as a test method and report whether it passes or fails. As long as all assertions (if any) pass and no exceptions are thrown, the test is considered to pass. So our test code should follow AAA (Arrange Act Assert) pattern.

  •  
    • Create student object that will be tested (arrange) - Student student = new Student("Joe", "Brian");
    • Exercise the production code’s Student.getdisplayStudentName() method(act) - String displayName = student.getdisplayStudentName();
    • Verify if the result is as expected (assert) - assertEquals("Joe, Brian", displayName); If the result did not match, the test would be marked as failed.

Unit Testing With JUnit

  • Production Code

public class Student { public String displayStudentName(String firstName, String lastName) {  return firstName + lastName; } }

  • Testing Code

Import org.junit.Test;
Import static org.junit.Assert.*;
Public class StudentTest {
 @Test
 Public void testDisplayStudentName() {
  Student student = new Student();
  String studentName = student.displayStudentName(“Anshuman”, ”Nain”);
  assertEquals(“AnshumanNain”, studentName);
 }
}

Now build the project and runUnit Testing With JUnit

Unit Testing With JMeter

Let’s test a login API (POST Method) using JMeter for performance testing. Below are the Steps for scripting the rest API -

  • First of all, we need to add an HTTP Request Sampler inside a thread group (Test Plan -> Thread Group -> Sampler->HTTP Request)

Unit Testing With JMeter - we need to add an HTTP Request Sampler inside a thread group

  • Next, we need to enter the Server Name or IP of the API and its port (if required) in the web server section.

Unit Testing With JMeter - enter the Server Name or IP of the API and its port (if required) in the web server section.

  • The user also needs to add HTTP Header Manager as a child to the HTTP Request sampler (for the current example this is not required) with the content-type header.

Unit Testing With JMeter - add HTTP Header Manager as a child to the HTTP Request sampler

  • At last, we add different listeners like 'Summary Report' to conclude.

Summary Report - Unit Testing With JMeter

Then finally run the test.Unit Testing With JMeter - run the testIn the above example, we hit 1000 requests per sec, out of which 992 were successful.

Unit Testing With Mockito

Basic Simple Demo code for using mockito with JUnit -

  • Production Code

public class TestService {
 public int getUniqueId() {
  return 43;
 }
}
  • Testing Code

public class JUnitServiceTestExample {

 @Test
 public void testGetInt() {
  // create mock
  TestService test = Mockito.mock(TestService.class);

  // define return value for method getUniqueId()
  when(test.getUniqueId()).thenReturn(43);

  // use mock in test....
  assertEquals(test.getUniqueId(), 43);
 }
}

Conclusion

In the end, it is safe to say that Test Driven Development must be adopted by as many developers as possible, in order increase their productivity and improve not only the code quality but also to increase the productivity and overall development of software/program. TDD also leads to more modularized, flexible and extensible code.

How Can XenonStack Help You?

We follow the Test Driven Development Approach in the development of Enterprise-level Applications following Agile Scrum Methodology.

Application Modernization

Re-platforming, re-hosting, recoding, rearchitecting, re-engineering, interoperability,  of the legacy Software application for current business needs is called Application Modernization. It services enable the migration of monolithic applications to new Microservices architecture with Native Cloud Support including the integration of new functionality to create new value from the existing application.

Java Cloud Services

Develop, Deploy and Manage Agile Java Application on leading Cloud Service Providers - Google Cloud, Microsoft Azure, AWS, and Container Environment - Docker and Kubernetes.

Continuous Integration and Continuous Deployment

Enable Secure Continuous Integration and Continuous Delivery Pipeline with Jenkins/ Bamboo/ TeamCity for delivery, automation, self-service environment, and On-demand. Deploy Java Application to production by decreasing the time by the automation of entire delivery pipeline comprising build, deploy, test, and release.

Microservices Architecture

Take a cloud-native approach to building Enterprise Applications for Web and Mobile with a Microservices Architecture. An Application based on Microservices Architecture is Small, Messaging–enabled, Bounded by contexts, Autonomously developed, Independently deployable, Decentralized, Language–agnostic, Built and released with automated processes.

Original article source at: https://www.xenonstack.com/

#java #test #developement 

How to Test Driven Development for Java using JUnit