IN Lately Gulp is gaining great popularity, and it’s clear why. It's faster, prettier and simpler than Grunt. I had to work with him often, but I always took ready-made solutions and didn’t fully understand how he did it all. This weekend I decided to disassemble and close this small problem. We'll talk about this today.

What is Gulp?

Gulp is a front build tool. It allows you to automate repetitive tasks (assembling and minifying CSS and JS files, running tests, restarting the browser, and others). Thus, Gulp speeds up and optimizes the web development process.

Installing Gulp

Installing Gulp is quite easy. If something doesn’t work out for you, write in the comments or Google your problem. So to install you need to take 3 steps:

  • Install Gulp globally
  • Install Gulp as devDependencies (development dependencies)
  • Create gulpfile.js file

The first step is to install Gulp globally. Open a terminal and write:

npm install --global gulp

After this you need to install Gulp as devDependencies for your project. Make sure you have a package.json file. If it does not exist, then create it by writing npm init to the console. Now you can install Gulp as devDependencies:

npm install --save-dev gulp

Finally, you need to create a gulpfile.js in the root of your project that will contain your tasks. As an intermediate step, we will install the gulp-util plugin. To show how plugins are installed:

npm install --save-dev gulp-util

Now it's time to write our first problem. Open the newly created gulpfile.js file and write the following into it:

/* File: gulpfile.js */ // collect all our plugins var gulp = require("gulp"), gutil = require("gulp-util"); // create a task that will be executed by default gulp. task (" default " , function () ( return gutil . log ( " Gulp is running! " ) ));

And now all we have to do is run gulp in the terminal and we will see something similar to this:

> gulp [ 12:32:08] Using gulpfile ~/Projects/gulp-scotch-io/gulpfile.js [ 12:32:08] Starting "default" ... [ 12:32:08] Gulp is running! [12:32:08] Finished "default" after 1 ms

Review

Gulp itself is very limited in features. But everything you need is included in separate plugins. They, together with Gulp, work wonders.

Gulp's API is very small, and contains only 4 higher-order functions:

  • gulp.task
  • gulp.src
  • gulp.dest
  • gulp.watch

gulp.task defines our tasks. Takes name, dependencies (array) and function (main actions) as arguments. There may not be any dependencies:

gulp. task (" mytask " , function () ( // do something )); gulp. task (" dependenttask ", [ " mytask " ], function () ( //do something after "mytask" is done });

gulp.src points to the files we want to use. It uses .pipe to access files via plugins.

gulp.dest points to the folder where we want to save the modified files.

gulp.src and gulp.dest are used for a simple copy of the files:

gulp. task("copyHtml", function()( // copy everything html files from source/ to public/ gulp. src("source/*.html"). pipe(gulp. dest(" public ")); ));

Gulp has a built-in system for responding to file changes (gulp.watch). You can use this task to run other tasks you need when files change.

In those days when websites were small, there was no need for a separate frontend assembly. However, the volume and complexity of CSS and JS were increasing, and the view in which it was convenient to develop became very different from the view in which the result should be presented to the user. Such tasks as concatenation (gluing) of files, code minimization, and even pre-compilation appeared. The result of this was specialized frontend assembly systems, which we will talk about.

Of course, as soon as the need for assembly became noticeable, the tools used by the backend immediately began to creep onto the frontend. Their main problem and the reason that in this moment they are used less and less for the frontend - they are not at all tailored to its specifics, since the project structure, the technologies used and the development cycle very much depend on the project’s tasks and can differ significantly. Ant, for example, has a verbose syntax and is not particularly able to do things necessary for the frontend: there are very few built-in tasks, and it is poorly extensible. If we talk about GNU make, then it is much more universal, since it operates with shell commands. Disadvantages include a special syntax that requires additional study, the need to know the shell well, and the tendency for Makefiles to quickly become more complex as build requirements increase.

Let's look at a medium-sized website with a standard structure and try to list the main stages of assembly that it goes through. For simplicity, let's assume that you don't bother creating different JS files for different pages, but at the same time you want to keep several small files in the development environment to maintain some kind of modularity. Usually it looks something like this:

/libs/ jquery.min.js underscore.min.js /js/ common.js carousel.js popups.js ....

The build system typically does the following:

  • concatenates all JS files into one (in the right order, we don’t want to load our scripts before jQuery);
  • checks JS code for validity (for example, using JSHint);
  • minimizes the code, obfuscates it if necessary (that is, makes it incomprehensible);
  • concatenates CSS files (the order is also important here, since properties are often overridden);
  • minimizes CSS;
  • puts the files in a separate directory, from which you include them in your HTML.

Often this simple circuit becomes more complicated additional requirements: tests are run, CSS preprocessor code is compiled, images are optimized, templates are compiled.

All these problems, and even more, can be solved modern instruments assemblies. We will consider the most popular solutions that work on the Node.js platform. Their common advantage is a clear language that all front-end developers know (or think they know), an initial focus on solving front-end problems, as well as an understandable Node.js environment in which you may already be developing your application.

Grunt

Grunt is the oldest, most important, and most popular build tool. Almost all of the build systems we review compare themselves to Grunt in one way or another, and some originated as faster or simpler alternatives. Despite this, it does have a couple of significant drawbacks.

First, as many front-end developers point out, Grunt is verbose. Setting up a simple build system will require a config of about a hundred lines. However, this in itself is not such a drawback: the config is quite easy to read, and due to the popularity of Grunt, finding a ready-made config for a typical task is usually not difficult.

Secondly, Grunt was developed as a universal product, that is, on its basis you can solve almost any problem related to assembling a project. It's cool, but it comes at a price for versatility. Both the aforementioned verbosity and speed. Compared to other Node.js build systems, Grunt is noticeably slower, and, most annoyingly, tends to slow down as the project grows. Without going into the details of Grunt's architecture, the reason is that every time you need to build, for example, a JS file, it rebuilds all the JS files. You can try to speed up the build process by manually specifying the necessary connections between files, but on a project with a complex tree of file dependencies this can be overly complicated.

Despite all this, Grunt has a huge ecosystem: hundreds of plugins, thousands of projects, billions of developers, that's all. That is, not only is Grunt universal, but a plugin for your task has most likely already been written.

To summarize, Grunt is a great choice for small to medium-sized projects, especially if you haven't set up any build systems before. A huge community, a bunch of plugins, clear documentation and even articles and reports in Russian for those unfortunate people who cannot live without it. And of course, if in the future for some reason Grunt no longer suits you, you can always switch to another system that is devoid of its shortcomings.

Gulp

Gulp is an actively developing build system at the moment. Its architecture is based on the use of threads in Node.js, which eliminates the need to write temporary files and folders to disk. The main advantages of Gulp are the speed and brevity of the config. Moreover, if the first is indisputable, then brevity in comparison with Grunt is achieved simply due to its different structure. If in the Grunt config you operate plugins individually, setting up each of them, then in the Gulp config you need to describe the process that each file (or set of files) must go through in order to be collected. Here's a real-life example of SASS compilation:

Gulp.task("styles", function() ( return gulp.src("styles/*.scss") .pipe(sass(( style: "expanded" ))) .pipe(rename((suffix: ".min "))) .pipe(minifycss()) .pipe(gulp.dest("build/styles/css")); ));

On the first line we register a Gulp task called styles. Then we sequentially describe what needs to be done with each of the files that matches the styles/*.scss mask: compile SASS, add .min to the file name, minify it, put it in the final directory. If we need to do something else with this file, we will simply add the appropriate command, for example .pipe (add ASCII unicorn comment to the beginning of the file) (hopefully for this daily tasks They will finally make a plugin). I like this approach to writing a config better: it better describes what actually happens to your files.

Of course, Gulp is still inferior to Grunt in terms of the number of plugins, but there are plugins for many tasks. Most likely, the existing plugins will be enough for you, and if something is really missing, you can always write your own (just kidding). By the way, there is a gulp-grunt package that allows you to run Grunt tasks from Gulp, if you really need to.

If you like this approach to building, speed is important, and you don't need to perform specific tasks that only Grunt has a plugin for, then Gulp could be a great choice. On currently Gulp remains Grunt's most serious competitor.

Broccolli

The youngest of the assembly tools under consideration is now, in fact, in the development stage. The developers of Broccolli do not hide the fact that they were inspired by Gulp, but they consider some of the concepts underlying it to be erroneous. For example, they chose to cache all intermediate build results (implemented by each of the plugins) to speed it up instead of partially rebuilding only the required files. They also didn’t like the fact that Gulp works best with the transformation of one file into one final one, that is, one to one. To improve many-to-one operations, Gulp is currently developing complex circuit with the creation of a virtual file system, which seems to the Broccolli developers to be an unnecessary complication and a manifestation of the weakness of the original Gulp concepts. Broccolli initially operates in terms of trees instead of files and only performs transformations of trees into other trees (even degenerate ones from the same vertex).

A very reasonable theoretical approach to the assembly problem does not solve the problem of the number of extensions to Broccolli. Unfortunately, there are about two dozen of them and they perform only the most basic tasks. If you want to try something new, look at Broccolli, it is fast enough, is actively being developed, but is probably still too raw for use on serious projects.

Brunch

Brunch was created with the same task - to beat Grunt on all fronts, but approached it from a completely different angle. Brunch developers decided to take a good understanding subject area, that is, make a less universal tool that will be tailored specifically to front-end tasks, for example, without any settings, understand that *.js is a file with scripts, *.coffee is CoffeeScript, and so on. Brunch is quite fast, much faster than Grunt, but slightly slower than Gulp. The undoubted advantages of Brunch also include a truly compact configuration, several times smaller than that of Grunt and Gulp. Here, for example, is a simple Brunch config:

Exports.config = files: javascripts: joinTo: "javascripts/app.js": /^app/ "javascripts/vendor.js": /^(bower_components|vendor)/ stylesheets: joinTo: "stylesheets/app.css" order :after: ["vendor/styles/helpers.css"] templates: joinTo: "javascripts/app.js"

Please note that the config can be written both in CoffeeScript (as in this case) and in regular JS. We create a regular module that returns JSON with build settings.

Pay attention to the joinTo and order keys. This is the domain knowledge I mentioned - at the config level, Brunch knows that you will most likely want to merge files, some before others. This is what allows you to replace 400 lines of the Grunt config with 20–30 lines of Brunch.

Plus, Brunch's ecosystem is much smaller than Grunt's and even Gulp's. There are about 50 plugins (compared to 450+ for Gulp, for example), development is not very fast, in general, everything is quite sad here.

To summarize: if you really like short configs, speed is important, but you don’t need any special actions at the build stage, then you can look at Brunch. Of course, the small number of plugins is confusing, but maybe the situation will change.

ENB

And finally, the sweetest part. I would like to tell you about the assembly system developed at Yandex by Marat Dulin, which is called ENB. This is what we are currently using in our project. Its approach is fundamentally different from all the systems described: it was originally created to work with projects using the BEM methodology, although, as the author notes, its platform is free from the BEM ideology and can be used for all projects of a suitable structure.

Briefly, that's the point. In ENB we operate with the concept of a target, that is, the final file that needs to be collected, or a node (folder, in general, a page) for which a certain set of files needs to be collected. In order to build the target file, we use a number of technologies (roughly speaking, plugins in Grunt terms, although the technologies are smaller and more specialized). First of all, ENB determines the initial set of files that are needed to assemble the targets (several basic technologies do this, working with the BEM methodology by default, that is, they look for a *.bemdecl file that contains the dependencies of a given node on different blocks), fully expands it's a dependency tree (when the block your page depends on is itself dependent on another, both are connected in the right order), and then finds the files needed for each registered technology. Then ENB follows the sequence of file transformations described in the config (here you can see some analogy with Gulp). Despite some differences from the standard approach of build systems, once you understand the basic concepts, further working with ENB is quite easy.

The main advantages of ENB: speed of assembly due to flexible system caching and the ability to exchange intermediate data between different technologies, parallelization of independent processes, and separation of the most difficult technologies into separate subprocesses. It is extremely easy to write new technologies for ENB if you are somehow dissatisfied with the behavior of the standard ones.

The disadvantages include the fact that the ENB config is quite verbose, since it is possible to control absolutely all stages of the build. Plus, ENB was still written for the BEM methodology, and attaching it to a project with a completely different structure will require unnecessary movements. There are not many technologies written for ENB (about 60), but it copes with most of the tasks of BEM projects with a bang.

To sum it up: ENB - the best choice for projects based on the BEM methodology, which I personally consider most suitable for medium and large sites, since organizing the code into blocks rules and beeps. It is very fast, collects dozens of pages and hundreds of files in seconds, is easy to set up and pleasant to use. If your project is large, you get confused in the code and edit files thousands of lines at a time, I advise you to study BEM in more detail as a way to organize the structure of front-end projects. And when you love BEM, you will love ENB as the most native tool for building BEM projects.

In this article we will analyze in detail the process of building a front-end project, which has taken root in my daily work and has greatly simplified the routine.
The article does not claim to be the ultimate truth, since today there are a large number of different assemblers and approaches to assembly, and everyone chooses to their taste. I will just share my thoughts on this topic and show my workflow.

We will use the Gulp picker. Accordingly, Node js must be installed on your system. We will not consider installing a node for a specific platform, because This can be Googled in a couple of minutes.
And first, I’ll answer the question - why Gulp?
Of the more or less tolerable alternatives, we have Grunt and Brunch.
When I just started getting involved with the collectors, both Grunt and Gulp were already on the market. The first one appeared earlier and therefore has a larger community and variety of plugins. According to npm:
Grunt - 11171 packages
Gulp - 4371 packages

But Grunt seemed too verbose to me. And after reading several comparison articles, I preferred Gulp for its simplicity and clarity.
Brunch is a relatively young project, with all the ensuing pros and cons. I'm watching it with interest, but haven't used it in my work yet.

Let's get started:

Let's create a folder for our project, for example "habr". Let's open it in the console and run the command

Npm init

You can simply press Enter on all the installer's questions, because... Now this is not important.
As a result, in the project folder we will generate a package.json file with approximately the following content

( "name": "habr", "version": "1.0.0", "description": "", "main": "index.js", "scripts": ( "test": "echo "Error: no test specified" && exit 1" ), "author": "", "license": "ISC" )

Let's modify it a little to suit our needs:

( "name": "habr", "version": "1.0.0", "description": "", "author": "", "license": "ISC", "devDependencies": ( "gulp": "^3.8.1" ) )

in the devDependencies block we indicated that we need gulp and will immediately register all our plugins.

Plugins:

With styles, I do the same thing as with js, but instead of rigger"a, I use the import built into SCSS.
Our main.scss will look like this:

/* * Third Party */ @import "CSS:../../bower_components/normalize.css/normalize.css"; /* * Custom */ @import "partials/app";

This way you can easily control the order in which styles are connected.
Let's check our task by running

Gulp style:build

Collecting pictures

The image task will look like this:

Gulp.task("image:build", function () ( gulp.src(path.src.img) //Select our pictures.pipe(imagemin(( //Compress them progressive: true, svgoPlugins: [(removeViewBox: false )], use: , interlaced: true ))) .pipe(gulp.dest(path.build.img)) //And throw it in build .pipe(connect.reload()); ));

I'm using imagemin's default settings, except for interlaced. You can read more about the API of this plugin.
Now, if we put some image in src/img and run the command

Gulp image:build

then we will see our optimized image in build. Gulp will also kindly write in the console how much space it has saved for users of our site :)

Fonts

I usually don’t need to do any manipulations with fonts, but in order not to break the “We work in src/ and build in build/” paradigm, I simply copy the files from src/fonts and paste them into build/fonts. Here's the task

Gulp.task("fonts:build", function() ( gulp.src(path.src.fonts) .pipe(gulp.dest(path.build.fonts)) ));

Now let's define a task called “build”, which will run everything we’ve coded here

Gulp.task("build", [ "html:build", "js:build", "style:build", "fonts:build", "image:build" ]);

File changes

In order not to climb into the console all the time, let's ask gulp to run the required task every time a file changes. To do this, write the following task:

Gulp.task("watch", function())( watch(, function(event, cb) ( gulp.start("html:build"); )); watch(, function(event, cb) ( gulp.start( "style:build"); )); watch(, function(event, cb) ( gulp.start("js:build"); )); watch(, function(event, cb) ( gulp.start("image :build"); )); watch(, function(event, cb) ( gulp.start("fonts:build"); )); ));

We understand there shouldn't be any problems. We simply follow our paths defined in the path variable, and in the function called when a file is changed - we ask to run the task we need.
Try running it in the console

Gulp watch

and change different files.
Well, isn't it cool?)

Web server

To enjoy the miracle of livereload, we need to create a local web server. To do this, we will write the following task:

Gulp.task("webserver", function() ( connect.server(( host: server.host, port: server.port, livereload: true )); ));

There’s not even anything to comment on here. We'll simply start the server with livereload on the host and port we defined in the server object.

Cleaning

If you add some image, then run the image:build task and then delete the image - it will remain in the build folder. So it would be convenient to clean it periodically. Let's create a simple task for this

Gulp.task("clean", function (cb) ( rimraf(path.clean, cb); ));

Now when you run the command

Gulp clean

The build folder will simply be deleted.

And finally, a little mercy

This task does not contain critical functionality, but I really like it :)

Gulp.task("openbrowser", function() ( opn("http://" + server.host + ":" + server.port + "/build"); ));

When we need it, we will launch it - and a tab with our project will automatically open in our browser.
That's cool :)

Final chord

The last thing is that we will define a default task that will launch our entire assembly.

Gulp.task("default", ["build", "webserver", "watch", "openbrowser"]);

Your final gulpfile.js will look something like this.
Now let's execute it in the console

And voila:) The blank for your project is ready and waiting for you.

A few words in conclusion

This article was intended as a way to once again brush up on the intricacies of building frontend projects, and to easily transfer this experience to new developers. You do not have to use this particular assembly option for your projects. There is yeoman.io, where you will find generators for almost any need.
I wrote this collector for two reasons.
- I like to use rigger in my html code
- Almost all assemblies that I have seen use a temporary folder (usually .tmp/) to record the intermediate results of the assembly. I don't like this approach and wanted to get rid of temporary folders.
- And I wanted to have all this out of the box :)

my working version you can download the builder on my github.

I hope the article was useful to you :)

P.S. about all errors, shortcomings and jambs - please write in a personal message

This manual contains a description of useful and most commonly used front-end tools. You will be able to learn the installation process of the tools and the main points of working with them.

NPM

Introduction

During the development of a project, it is often necessary to add third-party libraries and plugins. As a result, the developer needs to search for the required dependency, download, unpack the archive and copy the files into the project. Package managers will help automate this routine work.

Package Managersoftware, which allows you to manage the process of installing, uninstalling, configuring and updating various components.

Adding third-party libraries using a package manager is replaced by a couple of commands in the terminal.

One of the package managers used in frontend projects is NPM.

npm(Node.js Package Manager) is a package manager included with Node.js. Used to download packages from cloud server npm, or to upload packages to this server.

Official site

Beginning of work

To install npm you need to download and install NodeJS (npm will be installed automatically): https://nodejs.org/en/.

Usage

Installing packages

A package is one or more JavaScript files that represent some kind of library or tool. To install a package using npm, you need to run the following command:

Npm install<название пакета>

To install the package globally, use the key -g. After installation, the package along with the sources is located in the directory node_modules/.

Version check

To check the current npm version, you need to run the command:

Setting up a configuration file

File package.json contains information about your application: name, version, dependencies, etc. Any directory that contains this file is interpreted as a Node.js package.

To create a file package.json you need to run the command:

Npm init

After this, you will need to fill out some information about the project.

IN this file The names and versions of all packages needed in the project will be stored. Using the command npm install you can download all the packages that are in package.json.

To install a certain package and automatically save it in the package.json file, use the command:

Npm install<название пакета>--save-dev

Alternatives

Yarn

Peculiarities

  • Creating a web server and automatic reboot pages in the browser when saving code, tracking changes in project files.
  • Using various JavaScript, CSS and HTML preprocessors (CoffeeScript, Less, Sass, Stylus, Jade, etc.).
  • Minification of CSS and JS code, as well as optimization and concatenation separate files project into one.
  • Automatic creation of vendor prefixes (prefixes to the name CSS properties, which browser vendors add for non-standard properties) for CSS.
  • Managing files and folders within a project - creating, deleting, renaming.
  • Launch and execution control external teams operating system.
    Working with images - compression, creating sprites, resizing (png, jpg, svg, etc.).
  • Deploy (send to an external server) a project via FTP, SFTP, etc.
    Connecting and using an unlimited number of Node.js and Gulp utilities, programs and plugins in a project.
  • Creation of various project maps and automation of other manual labor.

Beginning of work

NodeJS and npm must be installed on the system.

Step 1: To install GulpJS globally using the npm package manager, you need to run the command:

Npm install gulp -g

Step 2: You need to install it for the application:

Npm install --save-dev gulp

Loading of additional plugins that can be used when building the project is also done using npm with the following command:

Npm install<название плагина>--save-dev

All installed plugins are in the directory node_modules/.

Usage

Step 1: First you need to connect gulp to the project. To do this in the file gulpfile.js write the line:

Var gulp = require("gulp");

Function require() allows you to connect plugins from the folder node_modules/.

Step 2: Using a variable gulp you can create tasks to build the project:

Gulp.task("exampleTask", function() ());

Method task takes two parameters: a name and a function with a task body.
This instruction can now be completed. To do this, write in the console:

Gulp exampleTask

Basic commands

Below is a more complex example of an instruction:

Gulp.task("exampleTask", function () ( return gulp.src("source-files") .pipe(plugin()) .pipe(gulp.dest("folder")); ));

Let's look at the commands used in in this example:

  • gulp.src– selection of project source files for processing by the plugin;
  • .pipe(plugin())– calling the Gulp plugin to process the file;
  • .pipe(gulp.dest('folder')) – output the resulting file to the destination folder.

File masks

The gulp.src function takes a file mask as a parameter. Examples of masks:

  • ./ – current directory;
  • ../ – parent directory;
  • js/index.js– index.js file in the js folder;
  • js/*.js– all files with the js extension in the js folder;
  • js/**/*.js– all files with the js extension in the js folder and in its subdirectories;
  • !js/*.js– exclusion of files with the js extension in the js folder.

Streams

The use of threads is one of the most important advantages of GulpJS.

Streams allow you to pass some data sequentially from one function to another, each of which performs some actions with this data.

Function gulp.src() creates a stream of objects representing the files passed to it as a parameter. Further using functions pipe a conveyor is built through which a flow of objects is transmitted. A plugin is passed to this function as a parameter, which in some way processes the stream of objects.

Below is an example of using threads. This example uses third-party plugins gulp-jshint And gulp-concat which need to be installed and connected to gulpfile.js.

Function gulp.src takes files by mask js/*.js. Runs JSHint and prints the result. Then it concatenates files and at the end saves the resulting file after concatenation in a directory dist/.

Gulp.task("example", function () ( return gulp.src("js/*.js") .pipe(jshint()) .pipe(concat("index.js")) .pipe(gulp.dest ("dist")); ));

Third party plugins

Let's look at an example of using third-party plugins. To do this, we will create an instruction for concatenating js files:

Step 1: First you need to enable the plugin with the require command:

Var concat = require("gulp-concat");

Step 2: Then you need to create a task for concatenating files with the js extension located in the js/ directory. At the end, the resulting file is placed in the dist/js directory:

Gulp.task("concat", function () ( return gulp.src("js/*.js") .pipe(concat("index.js")) .pipe(gulp.dest("dist/js") ); ));

Gulp concat

Additional Information

You can also define a task that will cause the execution of other tasks.

Gulp.task("build", ["html", "css"]);

In addition, there is a method watch to monitor changes in files:

Gulp.watch("mask of files to watch", ["name of the task that will be executed when files change"]);

IN gulpfile.js you can create a default task:

Gulp.task("default", ["task1", ​​"task2"]);

This task is launched from the console with the command:

Basic plugins

  • gulp-autoprefixer– automatically prefixes CSS properties;
  • gulp-browser-sync– creates a connection, after which it automatically refreshes the page when client or even server files change;
  • gulp-uncss– optimization of CSS files. The plugin analyzes HTML code and finds all unused and duplicated styles;
  • gulp-csso– CSS minifier;
  • gulp-htmlmin– simple HTML minifier;
  • gulp-htmlhint– HTML validator;
  • gulp-uglify– JavaScript minifier;
  • gulp-concat– file concatenation;
  • gulp-webserver– allows you to create and run a server;
  • gulp-jshint– checking the quality of JS code;
  • gulp-jasmine– running jasmine tests;
  • gulp-jsdoc– generation of JSDoc documentation.

WITH full list You can find Gulp plugins at the following link:
http://gulpjs.com/plugins/

Alternatives

GruntJS

Peculiarities

  • Asynchronous testing support.
  • The ability to place observers on different objects.

Beginning of work

To connect Jasmine to your project, you need to download the library and include the following files on the main HTML page:

  • lib/jasmine-*/jasmine.js- the framework itself;
  • lib/jasmine-*/jasmine-html.js- formatting the results in HTML form;
  • lib/jasmine-*/jasmine.css - appearance test results;
  • SpecRunner.html- a file that should be opened in the browser to run tests.

Synchronization with instruments

GulpJS

Jasmine can be included in the GulpJS project build:

Step 1: First you need to install the gulp-jasmine plugin:

Npm install gulp-jasmine --save-dev

Step 2: Then you need to connect the plugin in the assembly file and create a test launch task:

Var jasmine = require("gulp-jasmine"); gulp.task("jasmine", function() ( gulp.src("test files") .pipe(jasmine()); ));

KarmaJS

(working with this tool is described in more detail at the end of the article)

To connect Jasmine to KarmaJS you need:

Step 1: Install KarmaJS:

Npm install -g karma-cli

Step 2: Install the plugins necessary to run tests written in Jasmine in Chrome browsers and PhantomJS:

Npm install karma-jasmine karma-chrome-launcher karma-phantomjs-launcher

Step 3: Install Jasmine itself:

Npm install -g jasmine

Step 4: In the karma configuration file, connect the plugins and specify the path to the tests.

Usage

Keywords

  • describe – definition of a test set;
  • it – test definition;
  • expect – defines the expectations that are checked in the test.

The describe and it functions take two parameters: the first is the name, the second is the function with code.

Basic test example

describe(“test suite name”, function () ( it(“test name”, function () ( expect(2+2).toBe(4); )); ));

Methods for checking results

  • expect().toBe()– checking variables for equality (‘===’);
  • expect().not.toBe()– checking variables for equality (‘!==’);
  • expect().toEqual()– checking for equality of variables and objects, including contents;
  • expect().toBeDefined()– check for existence;
  • expect().toBeUndefined()– check for non-existence;
  • expect().toBeNull()– checking the variable value for null;
  • expect().toBeTruthy()– verification of truth;
  • expect().toBeFalsy()– check for falsity;
  • expect().toBeLessThan()– checking that the value must be less than;
  • expect().toBeGreaterThan()– checking that the value must be greater than;
  • expect().toBeCloseTo()– checking that the value must be close to the number;
  • expect().toMatch()– checking for compliance with a regular expression;
  • expect().toContain()– checking for content in the array;
  • expect().toThrow()– check for throwing an exception;
  • expect().toHaveBeenCalled()– checking the function call.

Additional functions

To avoid copying any logic used in tests, functions are used beforeEach/afterEach. They are run before/after each test respectively.

Functions are used to test asynchronous calls runs And waitsFor.

  • runs– accepts an asynchronous function for execution;
  • waitsFor– takes three parameters: the first is a function that should return true, if asynchronous call in function runs was executed, the second is an error message, the third is the wait in milliseconds.
describe(“an example of testing an asynchronous call”, function () ( var result = 0; function asyncFunc() ( setTimeout(function() ( result = result + 2; ), 500); ) it(“test name”, function ( ) ( runs(function () ( asyncFunc(); )); waitsFor(function() ( return result === 2; ), “the value has not changed”, 2000); )); ));

Observers

The ability to track function calls is done using spyOn. This function takes two parameters: the first is the object for which the function is called, the second is the name of the function that needs to be monitored.

If(“function call check”, function () ( spyOn(exampleObject, "exampleFunction"); exampleObject.exampleFunction(); expect(exampleObject.exampleFunction).toHaveBeenCalled(); ));

When tested using spyOn You can track the number of calls, their parameters and each call separately.

To create a function without implementation, you can use createSpy. Function createSpy takes a function name for identification.

If(“function call check”, function () ( var example = createSpy("EXAMPLE"); example(“param1”, “param2”); expect(example.identify).toHaveBeenCalledWith(“param1”, “param2”) ; expect(example.calls.length).toEqual(1); ));

Creating a stub object is done using createSpyObj. As parameters createSpyObj takes the name of the object and an array of strings, which is a list of methods of the stub object.

Alternatives

Mocha

Usage

Documentation is generated from source code comments.