1684839240
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.
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 Package | React 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.4 | 15.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 Package | For Library | Status |
---|---|---|
enzyme-adapter-preact-pure | preact | (stable) |
enzyme-adapter-inferno | inferno | (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:
chai-enzyme
with Mocha/Chai.jasmine-enzyme
with Jasmine.jest-enzyme
with Jest.should-enzyme
for should.js.expect-enzyme
for expect.Using Enzyme with React Native
Using Enzyme with Tape and AVA
Basic Usage
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
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
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
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()
wrapIf 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(/* ... */);
See the Contributors Guide
Organizations and projects using enzyme
can list themselves here.
Author: enzymejs
Source Code: https://github.com/enzymejs/enzyme
License: MIT license
1684419446
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.
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!}
}
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.
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
...
Add this to your package's pubspec.yaml
file:
dev_dependencies:
http_mock_adapter: ^0.4.4
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.
Now in your Dart code, you can use:
import 'package:http_mock_adapter/http_mock_adapter.dart';
All notable changes to this project will be documented in the CHANGELOG.md file.
See the AUTHORS file for information regarding the authors of the project.
http-mock-adapter is licensed under the permissive MIT License (LICENSE).
For information regarding contributions, please refer to CONTRIBUTING.md file.
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.
Now in your Dart code, you can use:
import 'package:http_mock_adapter/http_mock_adapter.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
1682609520
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:
This article covers three topics to help you start testing your Drupal project using 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:
(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.
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!
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.
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/
1682573890
Тестирование делает все лучше. Узнайте, как использовать Cypress для вашего сайта на Drupal.
Если вы не включаете тесты в свою разработку Drupal, скорее всего, это потому, что вы думаете, что это усложняет и увеличивает расходы без пользы. Cypress — это инструмент с открытым исходным кодом, обладающий множеством преимуществ:
В этой статье рассматриваются три темы, которые помогут вам начать тестирование вашего проекта Drupal с помощью Cypress:
Для целей этого руководства я предполагаю, что вы создали локальную среду разработки для своего проекта 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, где найти свои ресурсы и как найти все спецификации в вашем проекте.
Создайте новый каталог с именем 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. Помните 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/
1682570100
测试让一切变得更好。了解如何将 Cypress 用于您的 Drupal 网站。
如果您不在 Drupal 开发中包含测试,很可能是因为您认为它增加了复杂性和费用而没有好处。Cypress是一种开源工具,具有许多优点:
本文涵盖三个主题,可帮助您开始使用 Cypress 测试您的 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。
这些更改告诉赛普拉斯在哪里可以找到它的资源以及如何找到项目中的所有规范。
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。显然,提交输入的灵活样式阻碍了赛普拉斯“看到”输入的能力,因此它无法点击它。测试确实有效!
您也可以编写自己的自定义 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/
1681800488
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.
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");
}
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"){}
Void
OperatorThe 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)){}
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/
1681512300
Неопределенная переменная или что-то еще без значения всегда будет возвращать «неопределенное» в 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){}
Давайте теперь объясним каждый из этих методов более подробно.
Одним из первых методов, который приходит на ум, является прямое сравнение. Здесь вы сравниваете вывод, чтобы увидеть, возвращает ли он 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");
}
Мы также можем использовать тип переменной, чтобы проверить, является ли она undefined. К счастью для нас, undefined — это тип данных для неопределенного значения, как вы можете видеть ниже:
let name;
console.log(typeof name); // "undefined"
Теперь мы можем использовать тип данных для проверки undefined для всех типов данных, как мы видели выше. Вот как будет выглядеть проверка для всех трех рассмотренных нами сценариев:
if(typeof user.hobby === "undefined"){}
if(typeof scores[10] === "undefined"){}
if(typeof name === "undefined"){}
Оператор 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/
1681508520
一个未定义的变量或任何没有值的东西在 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){}
现在让我们更详细地解释这些方法中的每一个。
首先想到的方法之一是直接比较。这是您比较输出以查看它是否返回的地方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");
}
我们还可以使用变量的类型来检查它是否是undefined. 对我们来说幸运的是 undefined 是一个未定义值的数据类型,如下所示:
let name;
console.log(typeof name); // "undefined"
有了这个,我们现在可以使用数据类型来检查所有类型数据的未定义,就像我们上面看到的那样。以下是我们考虑过的所有三种情况的检查结果:
if(typeof user.hobby === "undefined"){}
if(typeof scores[10] === "undefined"){}
if(typeof name === "undefined"){}
运算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/
1681461490
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.
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");
}
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"){}
Void
OperatorThe 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)){}
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/
1679635200
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 -
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)
Author: ryh04x
Source Code: https://github.com/ryh04x/CEH-Exam-Questions
1678871100
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:
Web API:
GET /
prints runtime informationGET /version
prints podinfo version and git commit hashGET /metrics
return HTTP requests duration and Go runtime metricsGET /healthz
used by Kubernetes liveness probeGET /readyz
used by Kubernetes readiness probePOST /readyz/enable
signals the Kubernetes LB that this instance is ready to receive trafficPOST /readyz/disable
signals the Kubernetes LB to stop sending requests to this instanceGET /status/{code}
returns the status codeGET /panic
crashes the process with exit code 255POST /echo
forwards the call to the backend service and echos the posted contentGET /env
returns the environment variables as a JSON arrayGET /headers
returns a JSON with the request HTTP headersGET /delay/{seconds}
waits for the specified periodPOST /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
volumePOST/PUT /cache/{key}
saves the posted content to RedisGET /cache/{key}
returns the content from Redis if the key existsDELETE /cache/{key}
deletes the key from Redis if existsPOST /store
writes the posted content to disk at /data/hash and returns the SHA1 hash of the contentGET /store/{hash}
returns the content of the file /data/hash if existsGET /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 periodGET /swagger.json
returns the API Swagger docs, used for Linkerd service profiling and Gloo routes discoverygRPC API:
/grpc.health.v1.Health/Check
health checkingWeb UI:
To access the Swagger UI open <podinfo-host>/swagger/index.html
in a browser.
To install Podinfo on Kubernetes the minimum required version is Kubernetes v1.23.
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
kubectl apply -k github.com/stefanprodan/podinfo//kustomize
docker run -dp 9898:9898 stefanprodan/podinfo
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.
Author: Stefanprodan
Source Code: https://github.com/stefanprodan/podinfo
License: Apache-2.0 license
1678169051
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.
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.
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
Example:
class Test
def test(a)
b = a+2
return b
end
end
Test.new.test(15)
How does it work?
RBS file for Test:
class Test
def test: (Integer) -> Integer #test passes int as an argument and returns int.
end
What's new:
>> 1 => a
>> puts a #prints 1
>> O in 1 #returns false in the latest version, earlier it was giving an error.
>> def square (n) = n*n
>> 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
1677834300
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:
carton init
.carton dev
.carton test
.carton bundle
.carton sdk
.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.
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 tryrm -rf $(brew --prefix)/Library/Taps/swiftwasm/homebrew-tap/ && brew tap swiftwasm/tap
and retry again. Themaster
branch was renamed tomain
, 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.
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 version | SwiftWasm version | JavaScriptKit version | Tokamak version |
---|---|---|---|
0.15+ | 5.6 | 0.15+ | 0.10.1+ |
0.14 | 5.6 | 0.14 | 0.10 |
0.13 | 5.5 | 0.13 | 0.9.1 |
0.12.2 | 5.5 | 0.12 | 0.9.1 |
0.12.0 | 5.5 | 0.11 | 0.9.0 |
0.11.0 | 5.4 | 0.10.1 | 0.8.0 |
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.
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!)
carton dev
with the release
configurationBy default carton dev
will compile in the debug
configuration. Add the --release
flag to compile in the release
configuration.
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.
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.
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.
Author: swiftwasm
Source Code: https://github.com/swiftwasm/carton
License: Apache-2.0 license
1677786660
A repository of PSP programs performing several tests on the PSP platform.
The main idea behind this is having several files per test unit:
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.
The rest of this tutorial will assume that you installed the PSPSDK in C:\pspsdk.
Tip: If you see PSP Type A, you've connected the PSP in "USB mode". Disconnect, and run the PSPLINK game instead.
brew install libusb-compat
to install libusb.You are now ready to roll!
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.
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)
Author: Hrydgard
Source Code: https://github.com/hrydgard/pspautotests
License: View license
1677744420
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.
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 -
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 -
The major benefit of it is that it can easily be understood by a non-technical person also.
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.
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 -
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 -
Using Test-Driven Development concept in our programming skills -
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 -
It becomes easy to view what the error is, where it is and how it is paralyzing our code.
API Testing is one of the types of testing techniques. This type of technique is used in the following cases -
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 -
API Testing can be done by -
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 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.
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.
Ability to load and performs tests on many different applications/server/protocol types, some of them are listed below -
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.
The steps to set up environment for TDD in Java are listed below:
OR If it’s not a Maven project then download the JUnit jar and include it in your project.
The steps to implement Java TDD are described below:
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() |
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.
public class Student {
public String displayStudentName(String firstName, String lastName) {
return firstName + lastName;
}
}
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 run
Let’s test a login API (POST Method) using JMeter for performance testing. Below are the Steps for scripting the rest API -
Then finally run the test.In the above example, we hit 1000 requests per sec, out of which 992 were successful.
Basic Simple Demo code for using mockito with JUnit -
public class TestService {
public int getUniqueId() {
return 43;
}
}
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);
}
}
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.
We follow the Test Driven Development Approach in the development of Enterprise-level Applications following Agile Scrum Methodology.
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.
Develop, Deploy and Manage Agile Java Application on leading Cloud Service Providers - Google Cloud, Microsoft Azure, AWS, and Container Environment - Docker and Kubernetes.
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.
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/