DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Securing Your Software Supply Chain with JFrog and Azure
Register Today

JavaScript

JavaScript (JS) is an object-oriented programming language that allows engineers to produce and implement complex features within web browsers. JavaScript is popular because of its versatility and is preferred as the primary choice unless a specific function is needed. In this Zone, we provide resources that cover popular JS frameworks, server applications, supported data types, and other useful topics for a front-end engineer.

icon
Latest Refcards and Trend Reports
Trend Report
Modern Web Development
Modern Web Development
Refcard #363
JavaScript Test Automation Frameworks
JavaScript Test Automation Frameworks
Refcard #288
Getting Started With Low-Code Development
Getting Started With Low-Code Development

DZone's Featured JavaScript Resources

Automating the Migration From JS to TS for the ZK Framework

Automating the Migration From JS to TS for the ZK Framework

By Gordon Hsu
I was recently involved in the TypeScript migration of the ZK Framework. For those who are new to ZK, ZK is the Java counterpart of the Node.js stack; i.e., ZK is a Java full-stack web framework where you can implement event callbacks in Java and control frontend UI with Java alone. Over more than a decade of development and expansion, we have reached a code base of more than 50K JavaScript and over 400K Java code, but we noticed that we are spending almost the same amount of time and effort in maintaining Java and JavaScript code, which means, in our project, JavaScript is 8 times harder to maintain than Java. I would like to share the reason we made the move to migrate from JavaScript to TypeScript, the options we evaluated, how we automated a large part of the migration, and how it changed the way we work and gave us confidence. The Problem ZK has been a server-centric solution for more than a decade. In recent years, we noticed the need for cloud-native support and have made this the main goal of our upcoming new version, ZK 10. The new feature will alleviate servers’ burden by transferring much of the model-view-model bindings to the client side so that the server side becomes as stateless as possible. This brings benefits such as reduced server memory consumption, simplified load balancing for ZK 10 clustered backends, and potentially easier integration with other frontend frameworks. We call this effort “Client MVVM.” However, this implies huge growth of JavaScript code. As we are already aware that JavaScript is harder to maintain, it is high time that we made our JavaScript codebase easier to work with at 50k lines of code. Otherwise, extending the existing JavaScript code with the whole MVVM stack will become Sisyphean, if not impossible. We started to look at why Java has higher productivity and how we can bring the same productivity to our client side. Why Does Java Beat JavaScript at Large-Scale Development? What did Java get right to enable us an 8x boost in productivity? We conclude that the availability of static analysis is the primary factor. We design and write programs long before programs are executed and often before compilation. Normally, we refactor, implement new features, and fix bugs by modifying source code instead of modifying the compiler-generated machine code or the memory of the live program. That is, programmers analyze programs statically (before execution) as opposed to dynamically (during execution). Not only is static analysis more natural to humans, but static analysis is also easier to automate. Nowadays, compilers not only generate machine code from source code but also perform the sort of analysis that humans would do on source code like name resolution, initialization guards, dead-code analysis, etc. Humans can still perform static analysis on JavaScript code. However, without the help of automated static analyzers (compilers and linters), reasoning with JavaScript code becomes extremely error-prone and time-consuming. What value does the following JavaScript function return? It’s actually undefined instead of 1. Surprised? JavaScript function f() { return 1 } Compare this with Java, where we have the compiler to aid our reasoning “as we type." With TypeScript, the compiler will perform “automatic semicolon insertion” analysis followed by dead code analysis, yielding: Humans can never beat the meticulousness of machines. By delegating this sort of monotonous but critical tasks to machines, we can free up a huge amount of time while achieving unprecedented reliability. How Can We Enable Static Analysis for JavaScript? We evaluated the following 6 options and settled on TypeScript due to its extensive ECMA standard conformance, complete support for all mainstream JS module systems, and massive ecosystem. We provide a comparison of them at the end of the article. Here is a short synopsis. Google’s Closure Compiler: All types are specified in JSDoc, thereby bloating code and making inline type assertion very clumsy Facebook’s Flow: A much smaller ecosystem in terms of tooling and libraries compared to TypeScript Microsoft’s TypeScript: The most mature and complete solution Scala.js: Subpar; emitted JavaScript code ReScript: Requires a paradigm shift to purely functional programming; otherwise, very promising Semi-Automated Migration to TypeScript Prior to the TypeScript migration, our JavaScript code largely consisted of prototype inheritance via our ad-hoc zk.$extends function, as shown on the left-hand side. We intend to transform it to the semantically equivalent TypeScript snippet on the right-hand side. JavaScript Module.Class = zk.$extends(Super, { field: 1, field_: 2, _field: 3, $define: { field2: function () { // Do something in setter. }, }, $init: function() {}, method: function() {}, method_: function() {}, _method: function() {}, }, { staticField: 1, staticField_: 2, _staticField: 3, staticMethod: function() {}, staticMethod_: function() {}, _staticMethod: function() {}, }); TypeScript export namespace Module { @decorator('meta-data') export class Class extends Super { public field = 1; protected field_ = 2; private _field = 3; private _field2?: T; public getField2(): T | undefined { return this._field2; } public setField2(field2: T): this { const old = this._field2; this._field2 = field2; if (old !== field2) { // Do something in setter. } return this; } public constructor() { super(); } public method() {} protected method_() {} private _method() {} public static staticField = 1; protected static staticField_ = 2; private static _staticField = 3; public static staticMethod() {} protected static staticMethod_() {} private static _staticMethod() {} } } There are hundreds of such cases among which many have close to 50 properties. If we were to rewrite manually, it would not only take a very long time but be riddled with typos. Upon closer inspection, the transformation rules are quite straightforward. It should be subject to automation! Then, the process would be fast and reliable. Indeed, it is a matter of parsing the original JavaScript code into an abstract syntax tree (AST), modifying the AST according to some specific rules, and consolidating the modified AST into formatted source code. Fortunately, there is jscodeshift that does the parsing and consolidation of source code and provides a set of useful APIs for AST modification. Furthermore, there is AST Explorer that acts as a real-time IDE for jscodeshift so we can develop our jscodeshift transformation script productively. Better yet, we can author a custom typescript-eslint rule that spawns the jscodeshift script upon the presence of zk.$extends. Then, we can automatically apply the transformation to the whole codebase with the command eslint --fix. Let’s turn to the type T in the example above. Since jscodeshift presents us with the lossless AST (including comments), we can author a visitor that extracts the @return JSDoc of getter() if it can be found; if not, we can let the visitor walk into the method body of getter() and try to deduce the type T, e.g., deduce T to be string if the return value of getter() is the concatenation of this._field2 with some string. If still no avail, specify T as void, so that after jscodeshift is applied, the TypeScript compiler will warn us about a type mismatch. This way we can perform as much automated inference as possible before manual intervention and the sections required for manual inspection will be accurately surfaced by the compiler due to our fault injection. Besides whole file transformations like jscodeshift that can only run in batch mode, the typescript-eslint project allows us to author small and precise rules that update source code in an IDE, like VSCode, in real-time. For instance, we can author a rule that marks properties of classes or namespaces that begin or end with single underscores as @internal, so that documentation extraction tools and type definition bundlers can ignore them: TypeScript export namespace N { export function _helper() {} export class A { /** * Description ... */ protected doSomething_() {} } } TypeScript export namespace N { /** @internal */ export function _helper() {} export class A { /** * Description ... * @internal */ protected doSomething_() {} } } Regarding the example above, one would have to determine the existence of property-associating JSDoc, the pre-existence of the @internal tag, and the position to insert the @internal tag if missing. Since typescript-eslint also presents us with a lossless AST, it is easy to find the associating JSDoc of class or namespace properties. The only non-trivial task left is to parse, transform, and consolidate JSDoc fragments. Fortunately, this can be achieved with the TSDoc parser. Similar to activating jscodeshift via typescript-eslint in the first example, this second example is a case of delegating JSDoc transformation to the TSDoc parser upon a typescript-eslint rule match. With sufficient knowledge of JavaScript, TypeScript, and their build systems, one can utilize jscodeshift, typescript-eslint, AST Explorer, and the TSDoc parser to make further semantic guarantees of one’s codebase, and whenever possible, automate the fix with the handy eslint --fix command. The importance of static analysis cannot be emphasized enough! Bravo! Zk 10 Has Completely Migrated to TypeScript For ZK 10, we have actively undergone static analysis with TypeScript for all existing JavaScript code in our codebase. Not only were we able to fix existing errors (some are automatic with eslint --fix), thanks to the typescript-eslint project that enables lots of extra type-aware rules, we also wrote our own rules, and we are guaranteed to never make those mistakes ever again in the future. This means less mental burden and a better conscience for the ZK development team. Our Client MVVM effort also becomes much more manageable with TypeScript in place. The development experience is close to that of Java. In fact, some aspects are even better, as TypeScript has better type narrowing, structural typing, refinement types via literal types, and intersection/union types. As for our users, ZK 10 has become more reliable. Furthermore, our type definitions are freely available, so that ZK 10 users can customize the ZK frontend components with ease and confidence. In addition, users can scale their applications during execution with Client MVVM. Adopting TypeScript in ZK 10 further enables us to scale correctness during development. Both are fundamental improvements. Annex: Comparing Static Typing Solutions for JavaScript Google’s Closure Compiler Type system soundness unknown; Assumed as unsound, as sound type systems are rare @interface denotes nominal types whereas @record denotes structural types All type annotations are specified in comments leading to code bloat, and comments often go out of sync with the code. Most advanced and aggressive code optimization among all options listed here Find more information on GitHub Facebook’s Flow Unsound type system Nominal types for ES6 classes and structural types for everything else, unlike TypeScript where all types are structural; whereas in Java, all types are nominal Compared to TypeScript, Flow has a much smaller ecosystem in terms of tooling (compatible formatter, linter, IDE plugin) and libraries (TypeScript even has the DefinitelyTyped project to host type definitions on NPM) Find more information in Flow Documentation Microsoft’s TypeScript Supports all JavaScript features and follows the ECMA standard closely even for subtleties: class fields and TC39 decorators Seamless interoperation between all mainstream JavaScript module systems: ES modules, CommonJS, AMD, and UMD Unsound type system All types are structural, which is the most natural way to model dynamic types statically, but the ability to mark certain types as nominal would be good to have. Flow and the Closure Compiler have an edge in this respect. Also supports Closure-Compiler-style type annotations in comments Best-in-class tooling and a massive ecosystem; built-in support by VSCode; hence, its availability is almost ubiquitous Each enum variant is a separate subtype, unlike all other type systems we have ever encountered, including Rust, Scala 3, Lean 4, and Coq Find more information in The TypeScript Handbook Scala.js Leverages the awesome type system of Scala 3, which is sound Seamlessly shares build scripts (sbt) and code with any Scala 3 project The emitted JavaScript code is often bloated and sometimes less efficient than that of the Closure Compiler, Flow, and TypeScript. Learn more on the Scala.js site ReScript Touted to have a sound type system (where is the proof?) like that of Scala 3, but the syntax of ReScript is closer to JavaScript and OCaml The type system is highly regular like all languages in the ML family, allowing for efficient type checking, fast JavaScript emission, and aggressive optimizations. The emitted JavaScript code is very readable. This is a design goal of ReScript. Interoperation with TypeScript via genType As of ReScript 10.1, async/await is supported. Might require familiarity with more advanced functional programming techniques and purely functional data structures Learn more in the ReScript Language Manual documentation More
Three Scalable Next.js Architecture Boilerplate

Three Scalable Next.js Architecture Boilerplate

By Imamuzzaki Abu Salam
Next.js is a React framework that allows you to build server-side rendered React applications. It is a great tool for building web applications, but it can be difficult to scale your application as it grows. In this article, we will look at some of the best Next.js boilerplates for building scalable web applications. The community of Next.js developers has created a lot of boilerplates that you can use to start your project. These boilerplates are great for building scalable web applications. They are also easy to extend and maintain. In this article, we will look at some of the best Next.js boilerplates for building scalable web applications. Why We Need a Boilerplate A boilerplate is a template that you can use to start a new project. It contains all the necessary files and folders to get started with a project. It is a great way to save time and effort when starting a new project. By using a boilerplate, you can focus on the core features of your application instead of spending time setting up the project. It also helps you to follow best practices and patterns that are used by the community. What Is a Scalable Next.js Application? A scalable application is one that can handle a large number of users and requests. It is also easy to maintain and extend. It is important to build a scalable application from the beginning to avoid refactoring the code later. Scalability is a very important factor when building a web application. It is important to choose the right tools and architecture to build a scalable application. We always need to keep in mind that our application will grow in the future, not just becoming garbage that we bury in the GitHub repository. The Best Boilerplate for Building Scalable Next.js Applications There are many boilerplates available for building scalable Next.js applications. Here are some of the best boilerplates that you can use to start your project. Next.js Boilerplate by [alexeagleson] This boilerplate is a great starting point for building a Next.js application. It is built with TypeScript and uses Next.js 12. It also uses Tailwind CSS for styling. It is a great boilerplate for building a scalable web application. Feature Highlights Next.js 12 (you can help to upgrade to Next.js 13 in the repo) TypeScript Engine Locking ESLint Prettier Git Hooks (Husky) VS Code Config VS Code Debugging Storybook Component template Commit linting We can easily start a new project by cloning the repo and running the following commands: Shell ```bash gh repo clone alexeagleson/nextjs-fullstack-app-template # or git clone git@github.com:alexeagleson/nextjs-fullstack-app-template.git # or git clone https://github.com/alexeagleson/nextjs-fullstack-app-template.git # or you can also use degit if you want to use the template without git at first ``` If you need TailwindCSS or any styling framework, you still need to install it manually. But it's pretty good to kickstart this project. It has a lot of help, especially when we start with a team. It has a lot of good practices, and it's easy to maintain. It's also easy to extend and add new features. We can follow the guide to create new components or write our own CLI to automate the process. All sorts of linting and formatting are already set up. We can also use the VS Code config to make it easier to work with the project. It also has a Storybook config that we can use to build our components. This boilerplate has a commit-msg hook that we can use to link our commit message. We can easily document our component by using the Storybook. Click here for the repository. Click here for a full blog. Next.js Boilerplate by [ipenywis] He said in his explanation video of this boilerplate it's [The Senior React Project Setup You Need as a Junior Developer]. You can easily create architecture like a Senior. In today's fast-paced world of web development, it's essential to have the right tools and frameworks at your disposal. That's where the Next.js app with Turborepo, Zustand, TailwindCSS, and TypeScript stack comes in ¸— a powerful combination of cutting-edge technologies that can make your development process smoother, faster, and more efficient. One of the key benefits of this stack is Next.js, a top-tier framework for building server-side rendered React applications. It provides automatic code splitting, optimized performance, and easy deployment, making it an ideal choice for developers who want to focus on building robust and scalable web applications without worrying about the underlying infrastructure. Turborepo is another tool that can significantly improve your workflow by optimizing monorepo development. It enables developers to work with multiple packages within a single repository, saving tons of time and energy while making it easier to manage and maintain your codebase. Zustand is a lightweight state management library that offers a simple and intuitive approach to managing states in React applications. It can help you keep your codebase clean and organized while making it easy to work with and update your app's state. TailwindCSS is a utility-first CSS framework that can help you design responsive and customizable user interfaces with ease. With its intuitive utility classes and flexible customization options, you can create stunning designs that look great on any device or screen size. Finally, TypeScript adds static typing to the language, providing better type safety and developer experience. This can help catch bugs early and ensure that your codebase is clean and organized. Overall, the Next.js app with Turborepo, Zustand, TailwindCSS, and TypeScript stack is a powerful and modern choice for any developer looking to build cutting-edge web applications. While there may be a bit of a learning curve, the benefits are well worth the effort, including faster development times, improved performance, and easier maintenance of codebases. So why not give it a try and see for yourself? Just give it a shot. It's really good. It's easy to extend and maintain. Click here for the repository. Next.js Boilerplate by [T3] Create T3 App (CT3A) is a starter kit for building web applications using a specific set of modern technologies that form the T3 stack. The T3 stack consists of TypeScript, Express.js, and TypeORM. CT3A takes this stack and adds additional technologies to create a powerful and easy-to-use platform for building web applications. One of the standout features of CT3A is the use of TypeScript. The creators of CT3A believe that TypeScript provides a more consistent and less frustrating experience than vanilla JavaScript, especially for developers new to web development. With TypeScript, developers get live feedback as they write code, which helps prevent errors and saves time in the long run. Another key technology used in CT3A is Next.js, a popular web framework for building React-based applications. Next.js offers a lightly opinionated and heavily optimized approach to creating applications, which makes it easier for developers to make good decisions when building their apps. CT3A also makes use of tRPC, an alternative to GraphQL that provides a seamless client development experience against a typesafe server, without all the boilerplate. By leveraging TypeScript, tRPC provides an incredible developer experience that is easy to use and highly performant. In addition to these core technologies, CT3A also includes several other technologies that are commonly used in web development. These include Prisma, which provides end-to-end typesafety from the database to the app and offers a suite of tools to make daily interactions with the database easier. CT3A also uses Tailwind CSS, a popular utility-first CSS framework that makes it easy to create good-looking applications without worrying about naming classes or organizing files. Finally, CT3A includes NextAuth.js, a solution for bringing authentication and security to your Next.js application without the hassle of building it yourself. Overall, Create T3 App is a great starting point for anyone looking to build modern web applications using a powerful and easy-to-use set of technologies. With TypeScript, Next.js, tRPC, Prisma, Tailwind CSS, and NextAuth.js, CT3A provides a comprehensive and highly performant platform for building modern web applications. If you're looking to build web applications with the latest technologies and best practices, CT3A is definitely worth checking out. Conclusion That's all for today. I hope you find this article useful. If you have any questions or suggestions, please let me know in the comment section below. Thank you for reading. More
Playwright JavaScript Tutorial: A Complete Guide
Playwright JavaScript Tutorial: A Complete Guide
By Kailash Pathak
Using Render Log Streams to Log to Papertrail
Using Render Log Streams to Log to Papertrail
By Tyler Hawkins CORE
Why You Should Consider Using React Router V6: An Overview of Changes
Why You Should Consider Using React Router V6: An Overview of Changes
By Beste Bayhan
JavaScript Temperature Anomaly Chart
JavaScript Temperature Anomaly Chart

Hello! In this article, we will create a Temperature Anomaly chart. For this example, we will use the LightningCharts JS library, specifically the XY chart. For those interested in technical details, here are some of XY Chart characteristics: This type of chart works with only two axes, X and Y. It allows us to locate data points within the graph as coordinates. The XY chart is a great tool for measuring and reading temperature anomalies. Anomaly refers to a change from a reference or average value within an extended period of time. Positive values indicate that the temperature has been warmer, while negative values refer to a colder temperature. Main Uses of a Temperature Anomaly Chart Climate Monitoring: Temperature anomaly charts help monitor changes in temperature patterns over time, providing insights into climate trends and overall climate conditions. Climate Research: temperature anomaly charts have scientific use for studying climate dynamics, identifying climate drivers, and investigating the impact of natural and human-induced factors on temperature variations. Weather Forecasting: in meteorology, temperature anomaly charts are used to forecast weather patterns by identifying areas with unusual warmth or cold, contributing to more accurate short-term weather predictions. Environmental Analysis: Temperature anomalies affect ecosystems and environmental systems, making temperature anomaly charts valuable for analyzing the impacts of temperature variations on vegetation, wildlife, and ocean currents. Let's begin implementation. Template Setup 1. Please, download the following template (.ZIP), where you'll find the project and all required files to follow this tutorial. JavaScript Temperature Anomaly Chart Project Template. 2. Once you download the project, open it in Visual Studio, and visualize the following file tree: 3. Now, open a new terminal, and as usual in a NodeJS project, run the NPM install command. Refer to this article for more information on installing NodeJS. This would be everything for setting up the template. Now let's code. CHART.ts Inside this file, we will have all the logic needed to create our chart, configure animations, and format the data. 1. Importing the JSON data: JavaScript import data from './data.json' Ps. If you're new to JSON data, I recommend you this JSON data modeling guide. 2. Declare the constant lcjs that will refer to our @arction/lcjs library. 3. Extract required classes from lcjs. JavaScript const lcjs = require('@arction/lcjs') const { lightningChart, AxisTickStrategies, UIElementBuilders, UIOrigins, ImageFill, emptyLine, ImageFitMode, emptyFill, Themes } = lcjs 4. Creating the chart object: JavaScript const chart = lightningChart() .ChartXY({ theme: Themes.darkLime, }) .setTitle('') setTitle: Text that will be displayed as the top title in the dashboard. Theme: The LightningChart JS library features a collection of default implementations that can be accessed by Themes. The color theme of the components must be specified when it is created and can't be changed afterward. 5. Getting the Y axis: JavaScript const axisY1 = chart.getDefaultAxisY().setTitle('Atmospheric Carbon Dioxide (ppm)') The getDefaultAxisY, gives access to the Y axis, the same situation for the X axis (getDefaultAxisX). Once we have access to this, we can add UI properties like the title. AxisY1 corresponds to the meaning line in the chart: 6. Creating the main Y-Axis line: JavaScript const axisY2 = chart .addAxisY({ opposite: true, }) .setTitle('Temperature Anomaly Index (°C)') // Hide tick grid-lines from second Y axis. .setTickStrategy(AxisTickStrategies.Numeric, (ticks) => ticks .setMinorTickStyle((minor) => minor.setGridStrokeStyle(emptyLine)) .setMajorTickStyle((major) => major.setGridStrokeStyle(emptyLine)), ) The tick strategy defines the positioning and formatting logic of Axis ticks as well as the style of created ticks. The numeric property corresponds to the number values to be shown on the Y axis. For XY, the ticks will be empty lines because we don’t need to show each tick in the chart: JavaScript major.setGridStrokeStyle((solidLine) => solidLine.setThickness(500))), 7. X-axis: JavaScript const axisX = chart.getDefaultAxisX().setTickStrategy(AxisTickStrategies.DateTime) As you can see, the X axis has the Date Time strategy because we need to show the data by date: 8. Using the JSON data: JavaScript const { temperature, co2 } = data //code stored in "data.json" { "temperature":[-0.16,-0.08,-0.1,-0.17,-0.28,-0.33,-0.31,-0.36,-0.17,-0.1,-0.35,-0.22,-0.27,-0.31,-0.3,-0.23,-0.11,-0.11,-0.27,-0.18,-0.08,-0.16,-0.28,-0.37,-0.47,-0.26,-0.22,-0.39,-0.43,-0.49,-0.44,-0.44,-0.36,-0.35,-0.16,-0.15,-0.36,-0.46,-0.3,-0.28,-0.28,-0.19,-0.29,-0.27,-0.27,-0.22,-0.11,-0.22,-0.2,-0.36,-0.16,-0.1,-0.16,-0.29,-0.13,-0.2,-0.15,-0.03,0,-0.02,0.13,0.19,0.07,0.09,0.2,0.09,-0.07,-0.03,-0.11,-0.11,-0.17,-0.07,0.01,0.08,-0.13,-0.14,-0.19,0.05,0.06,0.03,-0.03,0.06,0.03,0.05,-0.2,-0.11,-0.06,-0.02,-0.08,0.05,0.03,-0.08,0.01,0.16,-0.07,-0.01,-0.1,0.18,0.07,0.16,0.26,0.32,0.14,0.31,0.16,0.12,0.18,0.32,0.39,0.27,0.45,0.4,0.22,0.23,0.32,0.45,0.33,0.46,0.61,0.38,0.39,0.54,0.63,0.62,0.53,0.68,0.64,0.66,0.54,0.66,0.72,0.61,0.65,0.68,0.74,0.9,1.01,0.92,0.85,0.98,1.02], "co2":[285.2,285.1,285,285,284.9,285.1,285.4,285.6,285.9,286.1,286.4,286.6,286.7,286.8,286.9,287.1,287.2,287.3,287.4,287.5,287.7,287.9,288,288.2,288.4,288.6,288.7,288.9,289.5,290.1,290.8,291.4,292,292.5,292.9,293.3,293.8,294,294.1,294.2,294.4,294.6,294.8,294.7,294.8,294.8,294.9,294.9,294.9,295.3,295.7,296.2,296.6,297,297.5,298,298.4,298.8,299.3,299.7,300.1,300.6,301,301.3,301.4,301.6,302,302.4,302.8,303,303.4,303.7,304.1,304.5,304.9,305.3,305.8,306.2,306.6,307.2,307.5,308,308.3,308.9,309.3,309.7,310.1,310.6,311,311.2,311.3,311,310.7,310.5,310.2,310.3,310.3,310.4,310.5,310.9,311.3,311.8,312.2,312.6,313.2,313.7,314.3,314.8,315.34,316.18,317.07,317.73,318.43,319.08,319.65,320.23,321.59,322.31,323.04,324.23,325.54,326.42,327.45,329.43,330.21,331.36,331.92,333.73,335.42,337.1,338.99,340.36,341.57,342.53,344.24,345.72,347.15,348.93,351.47,353.15,354.29] } 9. Adding values to the Atmospheric Carbon Dioxide line: JavaScript const carbonDioxideSeries = chart .addLineSeries({ yAxis: axisY1, }) .setName('Atmospheric Carbon Dioxide (ppm)') // Data set contains PPM measurement values only. First measurement is from year 1880, and each consecutive measurement is 1 year after previous. .add( co2.map((ppm, i) => ({ y: ppm, x: new Date(1880 + i, 0, 1, 0, 0, 0, 0).getTime(), })), ) As you can see, a line series was added to the Y1 axis. The name was set to the series, and the data was mapped from the CO2 array object from the JSON data. We don't have a date value, so just add 1 consecutive year from 1880, to create a non-breaking line. 10. Adding the legend box: JavaScript // Add legend. const legend = chart.addLegendBox(undefined, { x: axisX, y: axisY1 }).add(chart) .setOrigin(UIOrigins.LeftTop) .setMargin(4) const positionLegendOnAxes = () => legend.setPosition({ x: axisX.getInterval().start, y: axisY1.getInterval().end }) positionLegendOnAxes() The legendbox is added to the meaning line (Y axis) and the unique X axis. setOrigin: Sets the position origin of this UiElement. setMargin: Set margin around the object in pixels. setPosition: Sets the position of this UiElement relative to its origin. getInterval: Get the currently applied axis scale interval. NPM Start For initializing the chart, open up a new terminal and run the npm start command. You'll see the local host path. Click on it and interact with the chart on your browser. And here, you can visualize the final chart: Conclusion In this article, we have created an implementation of an XY chart in a very simple way. In order to generate an XY chart, we just need to make use of the charXY() method. In this example, we have used the default values within the LC JS library, but in your case, you would only need an object of type JSON with the values that you need. Technically, the process should work as long as you use two arrays. Almost all of the code development was focused on chart customization, and the process how to load the data is quite easy to understand. Another important point is the use of the theme catalog, which allows us to generate a chart with a fairly complex appearance, but without the need to resort to external CSS classes. Definitely, LC JS helps to perform optimal jobs for less use of time performed. In case you have any questions, leave a comment with any code snippets, and I'll be happy to help! See you in the next article with more Data Visualization tutorials, Bye :)

By Omar Urbano
Angular Unit Testing With Karma and Jasmine
Angular Unit Testing With Karma and Jasmine

Angular unit testing checks isolated pieces of code in an Angular app. It allows users to add new features without interrupting any other part of their application. Jasmine is a JavaScript testing framework, and Karma is a node-based testing tool for JavaScript codes across multiple real browsers. This blog helps you get started with Angular unit testing leveraging Karma and Jasmine. Introduction to Angular Unit Testing First things first, you must have Angular installed on your machine. That is where you need to start Angular installation. If you already have Angular installed, feel free to skip the next step. Creating and managing an Angular project is quite easy. There are various competing libraries, frameworks, and tools that can resolve the problems. The Angular team has created Angular CLI, which is a command-line tool used to streamline your Angular projects. Angular CLI is installed via npm, so you are going to need to have Node installed on your machine. After Node is installed, you can run the following command in your terminal. The time it takes for installation to complete may change. After it is done, you can see Angular CLI’s version by typing the following command in your terminal. Now that you have Angular CLI installed, you are ready to create an Angular sample app. Run the following command in your terminal. ng new angular-unit-test-application After executing the command, you will be asked whether you want to add Angular routing. Type Y and press ENTER. You will then be asked to choose between several options of stylesheet formats for your app. It will take a few minutes, and once done; you will move to your testing app. Unit testing tests the isolated units of code. Unit tests aim to answer questions such as, Has the sort function ordered the list in the correct order? Was I able to think about the logic correctly? To answer these questions, it is critical to isolate the unit of code under test. That is because when you are testing the sort function, you don't want to be forced into creating related pieces, such as making any API calls to fetch the actual database data to sort. You are already aware that unit testing tests individual components of the software or app. The main motive behind this is to check that all the individual parts are working as intended. A unit is the smallest possible component of software that can be tested. Usually, it has several inputs and one output. Let’s jump into the Angular web app testing part. Run the following command in your terminal. After waiting for a few seconds, you will see a new window of your web browser open on a page looking like this, as you see below. Deciphering the Role of Karma and Jasmine in Angular Unit Testing What Is Karma Test Runner? Karma is a testing automation tool developed by the Angular JS team as it was getting difficult to test their own framework features with current tools. As a result, they developed Karma and transitioned it to Angular as the default test runner for apps developed with the Angular CLI. Apart from getting along with Angular, it offers flexibility to tailor Karma to your workflow. It has the option to test your code across different browsers and devices like tablets, phones, etc. Karma gives you options to substitute Jasmine with other testing frameworks like Mocha and QUnit. Here is the content of the karma.conf.js file in a sample project. What is Jasmine? Jasmine is a free as well as an open-source Behavior Driven Development (BDD) framework that tests JavaScript code and also goes well with Karma. Like Karma, it is also the suggested testing framework within the Angular documentation. The flow of how the test run looks like, Testing component add-organization.component.ts JavaScript import { TranslateService } from '@ngx-translate/core'; import { SharedService } from 'src/app/shared/services/shared.service'; import { Component, OnInit } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; import { appConstants, allowedFileFormat, AppRoutes } from 'src/app/app.constants'; import { SelectOption } from 'src/app/shared/interface/select-option'; import { OrganizationService } from '../organization.service'; import { getOrganizations } from 'src/app/shared/config/api'; import { Router, ActivatedRoute } from '@angular/router'; import { MatDialog } from '@angular/material/dialog'; import { ConfirmDialogComponent } from 'src/app/shared/components/confirm-dialog/confirm-dialog.component'; @Component({ selector: 'app-add-organization', templateUrl: './add-organization.component.html', styleUrls: ['./add-organization.component.scss'] }) export class AddOrganizationComponent implements OnInit { orgId: any; submitted = false; logoFileFormat = allowedFileFormat.logoFileFormat; logoFileSize = allowedFileFormat.logoFileSize; selectedImageLogo!: File; selectedImageLogoUrl = ''; countryOptions: SelectOption[] = []; menuList = [{ label: 'HOME', url: '' }, { label: 'ORGANIZATION', url: '/app/organization' }, { label: 'CREATE ORGANIZATION', url: '' }]; themeData: any; configurationTabStatus = true; loading = false; userData = [{name: 'name'}]; userCount = 15; undefinedVariable: any; currentStep = 1; completedSteps: number[] = []; orgForm = this.createForm(); constructor(private fb: FormBuilder, public sharedService: SharedService, public translateService: TranslateService, private route: Router, public organizationService: OrganizationService, private activatedRoute: ActivatedRoute, private confirmDialog: MatDialog) { } ngOnInit(): void { this.orgId = this.activatedRoute.snapshot.params['orgId']; if (this.orgId) { this.configurationTabStatus = false; } this.getCountries(); this.getOrganizationDetails(); } createForm() { return this.fb.group({ firstName: ['', [Validators.required, Validators.maxLength(200)]], lastName: ['', [Validators.required, Validators.maxLength(200)]], isActive: [true], email: ['', [Validators.required, Validators.email, Validators.maxLength(200)]], }); } get formControl() { return this.orgForm.controls; } isFieldInvalid(field: string) { return ( (this.formControl[field].invalid && this.formControl[field].touched) || (this.formControl[field].untouched && this.submitted && this.formControl[field].invalid) ); } displayFieldCss(field: string) { return { [appConstants.default.hasErrorClass]: this.isFieldInvalid(field), }; } onViewUser() { if (this.orgId) { this.sharedService.setOrganizationId(this.orgId); this.route.navigate([AppRoutes.userPath]); this.userData = []; this.submitted = false; this.userCount = 10; this.undefinedVariable = undefined; } else { this.route.navigate([AppRoutes.addUser]); this.userData = [{name: 'ZYMR'}]; this.submitted = true; this.userCount = 20; this.undefinedVariable = 'Test'; } } isCompleted = (step: any) => this.completedSteps.indexOf(step) !== -1; navigateToStep(step: any) { if(this.currentStep !== step && (this.orgId || this.isCompleted(step))) { switch (step) { case 1: this.route.navigate([AppRoutes.user + this.orgId]); break; case 2: this.route.navigate([AppRoutes.organization + this.orgId]); break; case 3: this.route.navigate([AppRoutes.userPath + this.orgId]); break; case 4: this.route.navigate([AppRoutes.addUser + this.orgId]); break; default: break; } } } changeOrgStatus(event: any) { if (this.orgId && !event.checked) { const confirmDialog = this.confirmDialog.open(ConfirmDialogComponent, { disableClose: true, data: { title: this.translateService.instant('COMMON.ACTION_CONFIRM.TITLE'), message: this.translateService.instant('ORGANIZATIONS.ORGANIZATIONS_DEACTIVE'), }, maxWidth: '100vw', width: '600px', }); if (confirmDialog) { confirmDialog.afterClosed().subscribe(result => { if (result === true) { this.formControl['isActive'].setValue(event.checked); } else { this.formControl['isActive'].setValue(!event.checked); } }); } } } onSubmit(): void { const formData = new FormData(); formData.append('firstName', this.formControl['firstName'].value); formData.append('lastName', this.formControl['lastName'].value); formData.append('isActive', this.formControl['isActive'].value); formData.append('email', this.formControl['email'].value); if (this.orgId) { formData.append('Id', this.orgId); this.createEditNewOrganization(formData, appConstants.methodType.put); } else { this.createEditNewOrganization(formData, appConstants.methodType.post); } } private createEditNewOrganization(formData: FormData, methodType: string): void { this.submitted = true; if (this.orgForm.invalid) { return; } this.sharedService.showLoader(); this.organizationService.postFile(getOrganizations, formData, methodType).subscribe({ next: (res: any) => { this.sharedService.responseHandler(res, true, true, true); if (this.sharedService.isApiSuccess(res)) { this.orgId = res.data; if (methodType === appConstants.methodType.post) { this.route.navigate([AppRoutes.editOrganization + '/' + this.orgId]); } else { this.getOrganizationDetails(); } } }, error: (err: any) => { this.sharedService.errorHandler(err); }, complete: () => this.sharedService.hideLoader() } ); } private getOrganizationDetails() { if (this.orgId) { this.loading = true; const apiUrl = getOrganizations + '/' + this.orgId; this.sharedService.showLoader(); this.organizationService.get(apiUrl).subscribe({ next: (res: any) => { if (this.sharedService.isApiSuccess(res)) { this.configurationTabStatus = false; this.selectedImageLogoUrl = res.data.imageURL ? (res.data.imageURL + '?modifiedDate=' + res.data.modifiedDate) : res.data.imageURL; const formattedData = this.organizationService.prepareOrganizationDetailsResponse(res.data); this.orgForm.patchValue(formattedData); } }, error: (err: any) => { this.sharedService.errorHandler(err); }, complete: () => { this.loading = false; this.sharedService.hideLoader(); } } ); } } private getCountries(): void { this.sharedService.getCountriesList().subscribe( (res: Array<SelectOption>) => { this.countryOptions = res; } ); } } add-organization.component.spec.ts JavaScript import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { AddOrganizationComponent } from './add-organization.component'; import { HttpClientModule } from '@angular/common/http'; import { RouterTestingModule } from '@angular/router/testing'; import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core'; import { ToastrModule } from 'ngx-toastr'; import { SharedModule } from 'src/app/shared/modules/shared.module'; import { OrganizationService } from '../organization.service'; import { appConstants, AppRoutes } from 'src/app/app.constants'; import { defer } from 'rxjs'; describe('AddOrganizationComponent', () => { let component: AddOrganizationComponent; let fixture: ComponentFixture<AddOrganizationComponent>; beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpClientModule, RouterTestingModule, SharedModule, ToastrModule.forRoot(), TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }) ], declarations: [AddOrganizationComponent], providers: [ OrganizationService ] }).compileComponents(); fixture = TestBed.createComponent(AddOrganizationComponent); component = fixture.componentInstance; }); it('should create', () => { expect(component).toBeTruthy(); }); it('should get organization Form', () => { component.createForm(); expect(component.formControl).not.toBeNull(); }); it('should page is in edit mode', () => { (component as any).activatedRoute = { snapshot: { params: { orgId: '123' } } }; spyOn((component as any), 'getCountries'); spyOn((component as any), 'getOrganizationDetails'); component.orgId = '123'; component.ngOnInit(); expect(component.configurationTabStatus).toBeFalsy(); }); it('should initialize country dropdown', waitForAsync(() => { const countryList = [{ value: 1, display: 'india', }]; spyOn((component as any).sharedService, 'getCountriesList').and.returnValue(promiseData(countryList)); (component as any).getCountries(); fixture.whenStable().then(() => { expect(component.countryOptions).toEqual(countryList); }); })); it('should be toggled to deactivated organization', waitForAsync(() => { component.orgId = '123'; component.createForm(); spyOn((component as any).confirmDialog, 'open').and.returnValue({ afterClosed: () => promiseData(true) }); component.changeOrgStatus({ checked: false }); fixture.whenStable().then(() => { expect(component.formControl['isActive'].value).toBeFalsy(); }); })); it('should be toggled activated organization', waitForAsync(() => { component.orgId = '123'; component.createForm(); spyOn((component as any).confirmDialog, 'open').and.returnValue({ afterClosed: () => promiseData(false) }); component.changeOrgStatus({ checked: false }); fixture.whenStable().then(() => { expect(component.formControl['isActive'].value).toBeTruthy(); }); })); it('should save organization details', () => { component.orgId = ''; const spy = spyOn((component as any), 'createEditNewOrganization'); component.onSubmit(); expect(spy).toHaveBeenCalled(); }); it('should update organization details', () => { component.orgId = '123'; const spy = spyOn((component as any), 'createEditNewOrganization'); component.onSubmit(); expect(spy).toHaveBeenCalled(); }); it('should save organization data on createEditNewOrganization call', waitForAsync(() => { component.createForm(); component.orgForm.patchValue({ lastName: 'name', firstName: 'vatNumber', email: 'test@gmail.com', }); spyOn((component as any).organizationService, 'postFile').and.returnValue(promiseData({ code: '', data: '123', message: '', status: appConstants.responseStatus.success })); const spy = spyOn((component as any).sharedService, 'showLoader'); const spyResponseHandler = spyOn((component as any).sharedService, 'responseHandler'); const navigateByUrlSpy = spyOn((component as any).route, 'navigateByUrl'); (component as any).createEditNewOrganization({}, appConstants.methodType.post); fixture.whenStable().then(() => { expect(spy).toHaveBeenCalled(); expect(spyResponseHandler).toHaveBeenCalled(); expect(navigateByUrlSpy).toHaveBeenCalled(); }); })); it('should update organization data on createEditNewOrganization call', waitForAsync(() => { component.createForm(); component.orgForm.patchValue({ lastName: 'name', firstName: 'vatNumber', email: 'test@gmail.com', }); spyOn((component as any).organizationService, 'postFile').and.returnValue(promiseData({ code: '', data: '123', message: '', status: appConstants.responseStatus.success })); const spy = spyOn((component as any).sharedService, 'showLoader'); const getOrganizationDetails = spyOn((component as any), 'getOrganizationDetails'); const spyResponseHandler = spyOn((component as any).sharedService, 'responseHandler'); (component as any).createEditNewOrganization({}, appConstants.methodType.put); fixture.whenStable().then(() => { expect(spy).toHaveBeenCalled(); expect(getOrganizationDetails).toHaveBeenCalled(); expect(spyResponseHandler).toHaveBeenCalled(); }); })); it('should org form invalid on createEditNewOrganization call', () => { component.createForm(); component.orgForm.patchValue({ name: 'name', }); (component as any).createEditNewOrganization({}, appConstants.methodType.post); expect(component.submitted).toBeTruthy(); }); it('should handle error while saving organization data on createEditNewOrganization call', waitForAsync(() => { component.createForm(); component.orgForm.patchValue({ lastName: 'name', firstName: 'vatNumber', email: 'test@gmail.com', }); spyOn((component as any).organizationService, 'postFile').and.returnValue(rejectPromise({ code: '', data: '', message: '', status: appConstants.responseStatus.error })); const spyResponseHandler = spyOn((component as any).sharedService, 'errorHandler'); (component as any).createEditNewOrganization({}, appConstants.methodType.post); fixture.whenStable().then(() => { expect(spyResponseHandler).toHaveBeenCalled(); }); })); it('should get organization details on getOrganizationDetails call', waitForAsync(() => { component.createForm(); component.orgId = '123'; const orgDetails = { lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', isActive: true }; spyOn((component as any).organizationService, 'get').and.returnValue(promiseData({ code: '', data: { lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', imageURL: 'http://www.test.com/img1', modifiedDate: '12-12-12', isActive: true }, status: appConstants.responseStatus.success, message: '' })); spyOn(component.sharedService, 'isApiSuccess').and.returnValue(true); spyOn(component.organizationService, 'prepareOrganizationDetailsResponse').and.returnValue(orgDetails); (component as any).getOrganizationDetails(); fixture.whenStable().then(() => { expect(component.selectedImageLogoUrl).toEqual('http://www.test.com/img1?modifiedDate=12-12-12'); expect(component.configurationTabStatus).toBeFalsy(); expect(component.orgForm.value).toEqual({ lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', isActive: true, }); }); })); it('should get organization details but imageUrl is empty on getOrganizationDetails call', waitForAsync(() => { component.createForm(); component.orgId = '123'; const orgDetails = { lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', isActive: true }; spyOn((component as any).organizationService, 'get').and.returnValue(promiseData({ code: '', data: { lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', imageURL: '', modifiedDate: '', isActive: true }, status: appConstants.responseStatus.success, message: '' })); spyOn(component.sharedService, 'isApiSuccess').and.returnValue(true); spyOn(component.organizationService, 'prepareOrganizationDetailsResponse').and.returnValue(orgDetails); (component as any).getOrganizationDetails(); fixture.whenStable().then(() => { expect(component.selectedImageLogoUrl).toEqual(''); expect(component.configurationTabStatus).toBeFalsy(); expect(component.orgForm.value).toEqual({ lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', isActive: true, }); }); })); it('should handle error while getting organization details on getOrganizationDetails call', waitForAsync(() => { component.createForm(); component.orgId = '123'; spyOn((component as any).organizationService, 'get').and.returnValue(rejectPromise({ code: '', data: {}, status: appConstants.responseStatus.error, message: '' })); const spy = spyOn(component.sharedService, 'errorHandler'); (component as any).getOrganizationDetails(); fixture.whenStable().then(() => { expect(spy).toHaveBeenCalled(); }); })); it('should return class on displayFieldCss', () => { component.createForm(); component.orgForm.controls['email'].setValue('invalid_email@@dotcom'); component.submitted = true; expect(component.displayFieldCss('email')).toEqual({ 'has-error': true }); }); it('should set organization id and navigate to user list page', () => { component.orgId = '123'; const spy = spyOn(component.sharedService, 'setOrganizationId'); const navigateSpy = spyOn((component as any).route, 'navigate'); component.onViewUser(); expect(spy).toHaveBeenCalled(); expect(navigateSpy).toHaveBeenCalled(); expect(component.userData.length).toEqual(0); expect(component.submitted).toBeFalsy(); expect(component.userCount).toBeLessThan(15); expect(component.undefinedVariable).toBeUndefined(); }); it('should navigate to add user page', () => { const navigateSpy = spyOn((component as any).route, 'navigate'); component.onViewUser(); expect(navigateSpy).toHaveBeenCalled(); expect(component.userData.length).toEqual(1); expect(component.userData).toEqual([{name: 'ZYMR'}]); expect(component.submitted).toBeTruthy(); expect(component.userCount).toBeGreaterThan(15); expect(component.undefinedVariable).toBeDefined(); }); describe('on step click', () => { let spyRoute: jasmine.Spy<any>; beforeEach(waitForAsync(() => { spyRoute = spyOn((component as any).route, 'navigate'); })); it('should be navigate to first main info step with event id', () => { component.completedSteps = [1,2]; component.currentStep = 2; component.orgId = '10'; component.navigateToStep(1); expect(spyRoute).toHaveBeenCalledWith([AppRoutes.user + component.orgId]); }); it('should be navigate to second event detail step with event id', () => { component.completedSteps = [1,2]; component.currentStep = 1; component.orgId = '10'; component.navigateToStep(2); expect(spyRoute).toHaveBeenCalledWith([AppRoutes.organization + component.orgId]); }); it('should be navigate to third particiant step with event id', () => { component.completedSteps = [1,2,3]; component.currentStep = 1; component.orgId = '10'; component.navigateToStep(3); expect(spyRoute).toHaveBeenCalledWith([AppRoutes.userPath + component.orgId]); }); it('should be navigate to fourth communication step with event id', () => { component.completedSteps = [1,2,3,4]; component.currentStep = 3; component.orgId = '10'; component.navigateToStep(4); expect(spyRoute).toHaveBeenCalledWith([AppRoutes.addUser + component.orgId]); }); it('should not navigate to any step', () => { component.completedSteps = [1,2,3,4,5]; component.currentStep = 3; component.orgId = null; component.navigateToStep(5); expect(spyRoute).not.toHaveBeenCalled(); }); }); }); export const rejectPromise = (msg: any) => defer(() => Promise.reject(msg)); export const promiseData = <T>(data: T) => defer(() => Promise.resolve(data)); So, in this component, you can see you have a test list of things which are listed below: 2. Angular reactive form validation 3. Conditional variable and routing calls 4. Multiple cases to cover branches and statement 5. Pop up modal with closing with yes and no 6. Submitting form data and calling the post API and also the error handling part will cover 7. Get organization details using the API calls So all of these things, you will test in our spec file. You can see in the above image it will cover all the statements, functions, branches, and all. There will be multiple things you will notice from the above code snippet. What each of these does is explained below: We use a describe to begin our test, and we gave the name of the component that we are testing inside it. we can execute some pieces of code before the execution of each spec. This functionality is beneficial for running the common code in the app. Inside the beforeEach, we have TestBed.ConfigureTestingModule. TestBed sets up the configurations and initializes the environment suitable for our test.ConfigureTestingModule sets up the module that allows us to test our component. You can say that it creates a module for our test environment and have declarations, imports, and providers inside it. Testing Service 1. Organization.service.ts JavaScript import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { HttpBaseService } from '../shared/services/httpbase/httpbase.service'; import { LanguageService } from '../shared/services/language/language.service'; @Injectable({ providedIn: 'root' }) export class OrganizationService extends HttpBaseService { constructor(httpClient: HttpClient, languageService: LanguageService) { super(httpClient, languageService); } prepareOrganizationListResponse(resList: any[]) { let organizationList: any = []; let organization: any = {}; resList.forEach(list => { organization.lastName = list.lastName, organization.firstName = list.firstName, organization.email = list.email, organization.isActive = list.isActive organizationList.push(organization); }); return organizationList; } prepareOrganizationDetailsResponse(res: any) { return { lastName: res.lastName, firstName: res.firstName, email: res.email, isActive: res.isActive }; } } 2. Organization.service.spec.ts JavaScript import { SharedModule } from 'src/app/shared/modules/shared.module'; import { HttpClientModule } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { TranslateModule, TranslateLoader, TranslateFakeLoader, TranslateService } from '@ngx-translate/core'; import { HttpBaseService } from '../shared/services/httpbase/httpbase.service'; import { SharedService } from '../shared/services/shared.service'; import { OrganizationService } from './organization.service'; import { OrganizationConfigurationApi, OrganizationListItemUI } from './organization.model'; describe('OrganizationService', () => { let service: OrganizationService; beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpClientModule, SharedModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }), ], providers: [ TranslateService, HttpBaseService, SharedService, { provide: MAT_DIALOG_DATA, useValue: {} }, { provide: MatDialogRef, useValue: {} } ] }).compileComponents(); service = TestBed.inject(OrganizationService); }); it('should be created', () => { expect(service).toBeTruthy(); }); it('should be return properly formatted organization list response', () => { let organization: any = {}; organization.lastName = 'lastName', organization.firstName = 'firstName', organization.email = 'test@gmail.com', organization.isActive = true, expect(service.prepareOrganizationListResponse( [ { lastName: 'lastName', firstName: 'firstName', email: 'test@gmail.com', isActive: true, } ] )).toEqual([organization]); }); it('should be return organization details response', () => { expect(service.prepareOrganizationDetailsResponse({ lastName: 'lastName',

By Haresh Kumbhani
Building the World's Most Resilient To-Do List Application With Node.js, K8s, and Distributed SQL
Building the World's Most Resilient To-Do List Application With Node.js, K8s, and Distributed SQL

Developing scalable and reliable applications is a labor of love. A cloud-native system might consist of unit tests, integration tests, build tests, and a full pipeline for building and deploying applications at the click of a button. A number of intermediary steps might be required to ship a robust product. With distributed and containerized applications flooding the market, so too have container orchestration tools like Kubernetes. Kubernetes allows us to build distributed applications across a cluster of nodes, with fault tolerance, self-healing, and load balancing — plus many other features. Let’s explore some of these tools by building a distributed to-do list application in Node.js, backed by the YugabyteDB distributed SQL database. Getting Started A production deployment will likely involve setting up a full CI/CD pipeline to push containerized builds to the Google Container Registry to run on Google Kubernetes Engine or similar cloud services. For demonstration purposes, let’s focus on running a similar stack locally. We’ll develop a simple Node.js server, which is built as a docker image to run on Kubernetes on our machines. We’ll use this Node.js server to connect to a YugabyteDB distributed SQL cluster and return records from a rest endpoint. Installing Dependencies We begin by installing some dependencies for building and running our application. Docker Desktop Docker is used to build container images, which we’ll host locally. Minikube Creates a local Kubernetes cluster for running our distributed and application YugabyteDB Managed Next, we create a YugabyteDB Managed account and spin up a cluster in the cloud. YugabyteDB is PostgreSQL-compatible, so you can also run a PostgreSQL database elsewhere or run YugabyteDB locally if desired. For high availability, I’ve created a 3-node database cluster running on AWS, but for demonstration purposes, a free single-node cluster works fine. Seeding Our Database Once our database is up and running in the cloud, it’s time to create some tables and records. YugabyteDB Managed has a cloud shell that can be used to connect via the web browser, but I’ve chosen to use the YugabyteDB client shell on my local machine. Before connecting, we need to download the root certificate from the cloud console. I’ve created a SQL script to use to create a todos table and some records. SQL CREATE TYPE todo_status AS ENUM ('complete', 'in-progress', 'incomplete'); CREATE TABLE todos ( id serial PRIMARY KEY, description varchar(255), status todo_status ); INSERT INTO todos (description, status) VALUES ( 'Learn how to connect services with Kuberenetes', 'incomplete' ), ( 'Build container images with Docker', 'incomplete' ), ( 'Provision multi-region distributed SQL database', 'incomplete' ); We can use this script to seed our database. Shell > ./ysqlsh "user=admin \ host=<DATABASE_HOST> \ sslmode=verify-full \ sslrootcert=$PWD/root.crt" -f db.sql With our database seeded, we’re ready to connect to it via Node.js. Build a Node.js Server It’s simple to connect to our database with the node-postgres driver. YugabyteDB has built on top of this library with the YugabyteDB Node.js Smart Driver, which comes with additional features that unlock the powers of distributed SQL, including load-balancing and topology awareness. Shell > npm install express > npm install @yugabytedb/pg JavaScript const express = require("express"); const App = express(); const { Pool } = require("@yugabytedb/pg"); const fs = require("fs"); let config = { user: "admin", host: "<DATABASE_HOST>", password: "<DATABASE_PASSWORD>", port: 5433, database: "yugabyte", min: 5, max: 10, idleTimeoutMillis: 5000, connectionTimeoutMillis: 5000, ssl: { rejectUnauthorized: true, ca: fs.readFileSync("./root.crt").toString(), servername: "<DATABASE_HOST>", }, }; const pool = new Pool(config); App.get("/todos", async (req, res) => { try { const data = await pool.query("select * from todos"); res.json({ status: "OK", data: data?.rows }); } catch (e) { console.log("error in selecting todos from db", e); res.status(400).json({ error: e }); } }); App.listen(8000, () => { console.log("App listening on port 8000"); }); Containerizing Our Node.js Application To run our Node.js application in Kubernetes, we first need to build a container image. Create a Dockerfile in the same directory. Dockerfile FROM node:latest WORKDIR /app COPY . . RUN npm install EXPOSE 8000 ENTRYPOINT [ "npm", "start" ] All of our server dependencies will be built into the container image. To run our application using the npm start command, update your package.json file with the start script. JSON … "scripts": { "start": "node index.js" } … Now, we’re ready to build our image with Docker. Shell > docker build -t todo-list-app . Sending build context to Docker daemon 458.4MB Step 1/6 : FROM node:latest ---> 344462c86129 Step 2/6 : WORKDIR /app ---> Using cache ---> 49f210e25bbb Step 3/6 : COPY . . ---> Using cache ---> 1af02b568d4f Step 4/6 : RUN npm install ---> Using cache ---> d14416ffcdd4 Step 5/6 : EXPOSE 8000 ---> Using cache ---> e0524327827e Step 6/6 : ENTRYPOINT [ "npm", "start" ] ---> Using cache ---> 09e7c61855b2 Successfully built 09e7c61855b2 Successfully tagged todo-list-app:latest Our application is now packaged and ready to run in Kubernetes. Running Kubernetes Locally With Minikube To run a Kubernetes environment locally, we’ll run Minikube, which creates a Kubernetes cluster inside of a Docker container running on our machine. Shell > minikube start That was easy! Now we can use the kubectl command-line tool to deploy our application from a Kubernetes configuration file. Deploying to Kubernetes First, we create a configuration file called kubeConfig.yaml which will define the components of our cluster. Kubernetes deployments are used to keep pods running and up-to-date. Here we’re creating a cluster of nodes running the todo-app container that we’ve already built with Docker. YAML apiVersion: apps/v1 kind: Deployment metadata: name: todo-app-deployment labels: app: todo-app spec: selector: matchLabels: app: todo-app replicas: 3 template: metadata: labels: app: todo-app spec: containers: - name: todo-server image: todo ports: - containerPort: 8000 imagePullPolicy: Never In the same file, we’ll create a Kubernetes service, which is used to set the networking rules for your application and expose it to clients. YAML --- apiVersion: v1 kind: Service metadata: name: todo-app-service spec: type: NodePort selector: app: todo-app ports: - name: todo-app-service-port protocol: TCP port: 8000 targetPort: 8000 nodePort: 30100 Let’s use our configuration file to create our todo-app-deployment and todo-app-service. This will create a networked cluster, resilient to failures and orchestrated by Kubernetes! Shell > kubectl create -f kubeConfig.yaml Accessing Our Application in Minikube Shell > minikube service todo-app-service --url Starting tunnel for service todo-app-service. Because you are using a Docker driver on darwin, the terminal needs to be open to run it. We can find the tunnel port by executing the following command. Shell > ps -ef | grep docker@127.0.0.1 503 2363 2349 0 9:34PM ttys003 0:00.01 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -N docker@127.0.0.1 -p 53664 -i /Users/bhoyer/.minikube/machines/minikube/id_rsa -L 63650:10.107.158.206:8000 The output indicates that our tunnel is running at port 63650. We can access our /todos endpoint via this URL in the browser or via a client. Shell > curl -X GET http://127.0.0.1:63650/todos -H 'Content-Type: application/json' {"status":"OK","data":[{"id":1,"description":"Learn how to connect services with Kuberenetes","status":"incomplete"},{"id":2,"description":"Build container images with Docker","status":"incomplete"},{"id":3,"description":"Provision multi-region distributed SQL database","status":"incomplete"}]} Wrapping Up With a distributed infrastructure in place in our application and database tiers, we’ve developed a system built to scale and survive. I know, I know, I promised you the most resilient to-do app the world has ever seen and didn’t provide a user interface. Well, that’s your job! Extend the API service we’ve developed in Node.js to serve the HTML required to display our list. Look out for more from me on Node.js and distributed SQL — until then, keep on coding!

By Brett Hoyer
Top Six React Development Tools
Top Six React Development Tools

React, a popular JavaScript library for building user interfaces, has gained widespread adoption among web developers due to its flexibility, performance, and reusability. As React applications become more complex, having the right tools in your arsenal can greatly enhance your productivity and streamline your development workflow. In this article, we will explore the six best tools for React development that can help you build better, faster, and more efficient React applications. React DevTools React DevTools is an essential tool for React developers that allows you to inspect, debug, and profile React components in real time. It provides a set of powerful features, such as a component tree view, props and state inspection, a time-traveling debugger, and performance profiling, which can greatly aid in understanding and optimizing the behavior of your React applications. With React DevTools, you can gain insights into how your components are rendered, identify performance bottlenecks, and troubleshoot issues more effectively. Top Features of React DevTools Component Tree View: You can visualize the hierarchical structure of your React components. You can inspect the props and state of each component, view the component's rendered output, and even modify props and state in real time to see how it affects the component's behavior. Props and State Inspection: You’ll get detailed information about the props and state of each component, making it easy to inspect the data that's flowing through your React application. You can see the values of props and state, track changes over time, and even view the component's update history. Time-Traveling Debugger: You have the option to time-travel through the lifecycle of a component, making it easy to understand how a component's props and state change over time. You can step backward and forward through the component's updates, inspect the props and state at each point in time, and even revert to a previous state to reproduce and fix bugs. Performance Profiling: React DevTools includes a built-in profiler that helps you identify performance bottlenecks in your React application. You can profile the rendering performance of your components, view the time spent on each update, and analyze the component's update patterns to optimize performance and reduce unnecessary renders. Highlight Updates: You can efficiently highlight components that are updating frequently, making it easy to identify components that may be causing unnecessary renders. You can see which components are updating and how often, helping you identify performance issues and optimize your React application. Filter and Search: React DevTools provides powerful filtering and searching capabilities, allowing you to quickly find and inspect specific components or DOM elements in your React application. You can filter components by name, type, or update status, and even search for components based on their props or state values. Multiple React Versions: This React tool supports multiple versions of React, making it compatible with different projects that may be using different versions of React. You can switch between different React versions in the DevTools settings, allowing you to inspect and debug React applications with different dependencies. Accessibility Inspection: React DevTools includes an accessibility inspection feature that helps you identify and fix accessibility issues in your React components. You can check for accessibility violations, view accessibility properties, and get recommendations for improving the accessibility of your React application, ensuring that your UI is accessible to all users. Redux DevTools If you're using Redux, a popular state management library for React, Redux DevTools is a must-have tool. It provides a set of powerful features for inspecting and debugging Redux stores, including actions, state changes, and middleware. Redux DevTools also offers advanced features like a time-traveling debugger, which allows you to step through the history of your Redux store and replay actions, making it easier to understand and troubleshoot complex state management logic. Top Features of Redux DevTools Time Travel: React developers can easily time travel through the state changes in their Redux store. They can replay past actions, inspect the state at different points in time, and understand how the state changes throughout an application's execution. Action Monitoring: Redux DevTools logs all dispatched actions in the application, providing a comprehensive history of the actions that have been triggered. Developers can inspect the details of each action, including its type, payload, and metadata, to understand how the state changes in response to different actions. State Inspection: You’ll get a visual representation of the current state of the Redux store. Developers can inspect the state tree, view the values of individual properties, and track changes to the state in real-time as actions are dispatched. Time-Traveling Debugger: It includes a debugger that allows developers to set breakpoints, step through code, and inspect the state and actions at each step. This can be extremely helpful for understanding how the state changes in response to different actions and debugging complex Redux-based applications. Action Replay: The developers can quickly replay past actions, which can be useful for reproducing and fixing bugs. Developers can select a specific action from the action history and replay it to see how it affects the state and flow of the application. Middleware Support: It supports middleware, which are functions that intercept actions before they reach the reducers. This allows developers to inspect and modify actions before they are processed by the Redux store, providing powerful debugging capabilities. Keyboard Shortcuts: This impressive tool provides a range of keyboard shortcuts that make it easy to navigate and interact with the tool. This can help developers quickly access different features and perform common actions, improving their productivity. Integration with the Redux Ecosystem: Redux DevTools integrates seamlessly with the broader Redux ecosystem, including popular libraries like Redux Thunk, Redux-Saga, and Redux Observable. This allows developers to inspect and debug the behavior of these middleware and other Redux-related tools. Customization: You’ll get a wide range of customization options, allowing developers to configure the tool to suit their preferences and workflow. Developers can customize the appearance, behavior, and features of Redux DevTools to match their specific needs. Create a React App Create React App is a popular command-line tool that allows you to quickly bootstrap a new React project with a preconfigured development environment. It sets up a minimalistic yet powerful development setup with modern features such as hot module replacement, which allows you to see changes in your code without refreshing the page, and a built-in development server with automatic error reporting. Create React App also comes with a set of built-in scripts for common development tasks, such as building and deploying your React application, making it a great tool for getting started with React development. Top Features of the Create React App Zero Configuration: You can efficiently deal with a pre-configured setup for a React application out of the box, eliminating the need for developers to configure and set up various build tools and dependencies manually. This allows developers to quickly start building React applications without spending time on initial setup. Developer Experience (DX): Create React App prioritizes the developer experience by providing features such as hot module replacement, which allows for fast and seamless development with automatic reloading of changes without requiring a full page refresh. It also includes helpful error messages with detailed stack traces for easier debugging. Production-Ready Builds: You can generate optimized, and production-ready builds for React applications. It automatically optimizes assets, minifies code, and performs other performance optimizations to ensure that the production builds are efficient and optimized for performance. Customizable Configuration: While Create React App comes with a sensible default configuration, it also provides options for customization. React developers can "eject" from the default setup and access and modify the underlying configuration files to tailor the build process to their specific requirements. Built-in Support for Modern JavaScript Features: This development tool supports modern JavaScript features such as ES6, ES7, and beyond, allowing developers to write modern JavaScript code without having to configure and set up transpilers manually. CSS and Style Support: It supports various CSS and styling options out of the box, including CSS modules, Sass, Less, and CSS-in-JS solutions like styled-components and emotion, making it easy for developers to choose their preferred styling approach. Development Server: Create React App includes a built-in development server that allows developers to run and test their React applications locally with automatic reloading and other development-friendly features. Extensibility: Create React App provides an extensible and pluggable architecture, allowing developers to add additional tools, libraries, and configurations to their React application as needed without ejecting from the default setup. Easy Deployment: Create React App generates production-ready builds that can be easily deployed to various hosting platforms or integrated into a continuous integration and deployment (CI/CD) pipeline for seamless deployment to production. Storybook Storybook is a powerful tool for building, documenting, and testing React components in isolation. It provides a development environment where you can create interactive component showcases with different variations and states, making it easier to visualize and test the behavior of your components in different scenarios. Storybook also comes with a set of add-ons for tasks such as accessibility testing, documentation generation, and visual testing, which can help you build more robust and accessible React applications. Top Features of a Storybook Component Isolation: Storybook allows developers to develop and test UI components in isolation, separate from the main application. This isolation makes it easier to identify and fix issues related to individual components without affecting the rest of the application. Component Explorer: Storybook provides a component explorer that acts as a visual documentation tool for UI components. It allows developers to browse through a visual catalog of components, views their various states, and interact with them to understand their behavior and usage. Interactive Development Environment (IDE): Storybook provides an interactive development environment where developers can create and edit components in real time. This makes it easy to experiment with different component configurations, styles, and interactions to fine-tune their appearance and behavior. Component Testing: Storybook comes with built-in testing capabilities, allowing developers to write and run tests for individual components. This helps in identifying and fixing issues related to component functionality, behavior, and performance, ensuring the quality and reliability of the components. Customizable Themes and Styles: Storybook allows developers to customize the appearance and behavior of the component explorer to match their application's branding and styling. It provides support for custom themes, styles, and layouts, making it easy to integrate Storybook into existing design systems and workflows. Extensibility: Storybook is highly extensible and supports a wide range of plugins and add-ons. These plugins and addons can be used to enhance the functionality of Storybook, such as by adding support for different UI frameworks, integrating with third-party tools, and extending testing capabilities. Collaboration and Documentation: Storybook makes it easy for teams to collaborate on component development by providing features like built-in version control, documentation generation, and sharing of component stories. This makes it easier to maintain a consistent design system, document component usage, and share component examples across the team. Support for Multiple Frameworks: Storybook supports a variety of popular UI frameworks, such as React, Vue, Angular, and more. This makes it a versatile tool that can be used in different front-end development environments, allowing developers to work with their preferred UI framework. Hot Module Replacement (HMR): Storybook uses Hot Module Replacement (HMR) to provide a fast development experience by allowing developers to see changes in their components in real time without requiring a full page reload. This speeds up the development process and improves productivity. Addons Ecosystem: Storybook has a vibrant ecosystem of addons that provide additional functionality, such as design system integration, accessibility testing, internationalization, and more. These add-ons can be easily installed and configured, enhancing the capabilities of Storybook for specific use cases. ESLint ESLint is a popular JavaScript linter that can be configured to work seamlessly with React applications. It helps you enforce coding standards, catch common errors, and prevent potential bugs in your React codebase. ESLint comes with a set of predefined rules for React, and you can also configure custom rules based on your project's requirements. By integrating ESLint into your development workflow, you can catch coding mistakes early and ensure consistent code quality across your React application. Top features of ESLint Customizable Rules: ESLint allows developers to customize rules according to their project's specific coding standards. It comes with a default set of rules, but developers can configure it to suit their requirements. Extensibility: ESLint is highly extensible, allowing developers to create their own rules or use third-party plugins to enhance its functionality. This makes it flexible and adaptable to different coding styles and project requirements. Multiple Configuration Options: ESLint supports multiple configuration options, including configuration files (e.g., .eslintrc.js, .eslintrc.json, etc.), inline configuration comments, and shared configuration files. This allows developers to configure ESLint in a way that best fits their workflow. Support for ECMAScript Versions: ESLint supports different ECMAScript versions, including ES5, ES6/ES2015, ES2016, ES2017, ES2018, ES2019, ES2020, and ES2021. This makes it suitable for projects using different JavaScript language versions. Code Fixing: ESLint not only identifies coding errors but also provides automatic code-fixing suggestions for many common issues. Developers can use the --fix option to automatically fix issues reported by ESLint, which helps maintain code quality and consistency. Editor Integrations: ESLint has integrations with popular code editors such as VSCode, Sublime Text, Atom, and many others. These integrations provide real-time feedback, making it easier for developers to identify and fix issues as they write code. Support for Plugins and Shareable Configurations: You can quickly support plugins that can extend their functionality and shareable configurations that allow developers to define a set of rules and share them across projects. This makes it easy to maintain consistent coding standards across multiple projects. Wide Range of Rules: You can efficiently define a large number of built-in rules that cover various coding conventions, best practices, and potential issues. These rules help in catching coding errors, enforcing coding standards, and improving code quality. Command-line Interface (CLI): This dev tool provides a command-line interface (CLI) that allows developers to run it from the command line, making it suitable for integration into build systems and continuous integration (CI) pipelines. Active Community and Regular Updates: ESLint has a large and active community of users and contributors, which ensures regular updates, bug fixes, and improvements. It is actively maintained and widely used in the JavaScript ecosystem. React Router React Router is a powerful routing library for React that allows you to create declarative, client-side routing in your applications. It provides a set of routing components that you can use to define routes, nested routes, and route transitions, making it easier to handle navigation and URL routing in your React applications. React Router also comes with advanced features such as lazy loading, code splitting, and server-side rendering, which can help you optimize the performance and user experience of your React applications. Top features of React Router Declarative Routing: React Router allows developers to define routes using declarative syntax, making it easy to specify how different components should be rendered based on the URL. Routes can be defined as components, making it straightforward to manage the state and props of the routed components. Nested Routing: React Router supports nested routing, allowing developers to create complex route hierarchies with parent and child routes. This enables the creation of multi-level navigation structures and allows for more granular control over how components are rendered based on the URL. Dynamic Routing: It allows for dynamic routing, where routes can be generated based on data or user input. This makes it possible to create dynamic and data-driven user interfaces that can adapt to changing data or user interactions. Route Parameters: With its active support for route parameters, developers can define dynamic segments in URLs that can be used to pass data to components. This makes it possible to create dynamic and personalized views based on URL parameters. Redirects and Navigation: This React development tool provides built-in support for handling redirects and navigation between different routes within the application. This allows for smooth navigation between different views and enables developers to create intuitive user experiences. History API Integration: React Router integrates with the HTML5 History API, allowing for smooth navigation without page reloads. This enables a seamless user experience and allows for more efficient handling of routing in SPAs. Middleware Support: It has integral support for middleware, allowing developers to add custom logic or behavior during the routing process. This makes it possible to implement features such as authentication, authorization, and data fetching as part of the routing logic. Route Guards: React Router supports route guards, which are functions that can be used to protect routes based on certain conditions. Route guards can be used to implement authentication and authorization logic to restrict access to certain routes or views based on user roles or permissions. Linking and Navigation Components: React Router provides a set of built-in components for linking and navigation, such as Link and NavLink, which make it easy to create clickable links and navigation menus in the application. These components automatically handle URL updates and provide a consistent way to navigate between different routes. Extensibility: React Router is highly extensible and allows developers to customize its behavior by creating their route components, hooks, and higher-order components. This provides flexibility in managing routing logic and enables developers to tailor the routing behavior to their specific needs. In Summary React Developer Tools are essential for any React developer looking to streamline their development process, debug efficiently, and optimize their React applications for better performance. With its powerful features and intuitive interface, React Developer Tools is a must-have toolset for modern web development with React. Happy coding!

By Hardik Thakker
How To Use Face Recognition for Authentication in Vue.JS and Golang
How To Use Face Recognition for Authentication in Vue.JS and Golang

Face recognition, as a biometric recognition technology based on artificial intelligence, has been widely applied in many fields in recent years. In web applications, facial recognition-based identity authentication is also becoming increasingly popular. At the same time, the user experience continues to improve. This article will introduce how to integrate FaceIO in Vue.js and Golang to achieve identity authentication for facial recognition. In web applications, the security and convenience factors brought by facial recognition-based identity authentication can enhance the user experience. FaceIO, as a third-party technology service provider, provides facial identity recognition services based on artificial intelligence. Moreover, FaceIO provides an online JavaScript library. It can be integrated very easily into web applications. The reference to the online JavaScript library can be found in the following code: JavaScript <script src="https://cdn.faceio.net/fio.js"></script> The project code corresponding to this article has been uploaded to GitHub. The uploaded code is a complete project code. The code is based on the MIT protocol and has no restrictions. Plain Text Technology Stack Front-end: Vue.Js v2.7.14, Node.Js v18.13.0, JQuery Back-end: Golang v1.13.15 Development Tool: GoLand 2019 If you are interested, you can download it from GitHub. The UI framework for the front end of this project uses Bootstrap and references the use of Gentella. Take a screenshot of the login below Before integrating web applications, you need to first apply for a Public ID for your application from FaceIO's official website. The application process is very simple and offers a free trial count. This article will not introduce the application process. If you are interested, you can log in to FaceIO's official website to take a look. How To Integrate FaceIO in the Front End of Vue.js Step 1: Create Vue Engineering Files in the Development Tool GoLand This project uses Node.Js version 18.13.0. After installing the plugin Vue.js in GoLand, we can create Vue project files. To install plugins, you need to enter Vue.js in "File>Settings>Plugins" to find and install them. Step 2: Reference “fio.js” in Index. HTML in the Directory “Public” The code is shown below: HTML <body> <div id="app"></div> <!-- built files will be auto injected --> </body> <script src="https://cdn.faceio.net/fio.js"></script> <script src="ajaxScript.js"></script> <script src="jquery.min.js"></script> <script type="text/javascript"> let myFaceIO function initFaceIO(result) { myFaceIO = new faceIO(result.Result.FaceIOAppCode); window.myFaceIO=myFaceIO } jPost("config","",initFaceIO) </script> In the above code, use JQuery to obtain the Public ID registered by the web application in FaceIO from the back end. The purpose of this design is to prevent the Public ID from being directly exposed in the code. If the Public ID is written dead in the code, the flexibility is very low. In my customized JavaScript file "ajaxScript.js," I implemented a common function for communicating with the back-end through JQuery. The custom function jPost() is responsible for interacting with the back end. At the same time, after data interaction, call the callback function initFaceIO() in the result. All data interactions use JSON data format. In the callback function initFaceIO(), initialize the FaceIO object. Code for initializing FaceIO: JavaScript myFaceIO = new faceIO(result.Result.FaceIOAppCode); After initialization, use: JavaScript window.myFaceIO=myFaceIO This will make myFaceIO a global variable. It can take effect in Vue's framework code and can be used. Please note that the JavaScript files "ajaxScript.js" and "jquery.min.js" referenced here are both in the directory "public" and do not use Vue's library files. Step 3: How To Use FaceIO in the Vue Framework In this project, I used JQuery in the Vue framework and customized the JavaScript library file "scripts.js." In this JavaScript library file, JQuery has been re-encapsulated, and some operation functions have been customized. So, in order to be globally effective, a reference was made in the file "main.js." At the same time, the code also uses the UI framework Bootstrap, which needs to be referenced in the file "main.js." The code for the file "main.js" is shown below: Vue.js Component import Vue from 'vue' import App from './App.vue' import router from './router/index.js' import {AjaxPost} from './assets/build/js/scripts.js' import './assets/vendors/bootstrap/dist/css/bootstrap.min.css' import './assets/vendors/font-awesome/css/font-awesome.min.css' import 'bootstrap/dist/js/bootstrap.min.js' Vue.prototype.AjaxPost = AjaxPost Vue.config.productionTip = false new Vue({ el: '#app', router, render: h => h(App) }) Set the HTTP access address of the back-end service in the custom JavaScript library file "scripts.js" JavaScript const serverUrl='http://127.0.0.1:8888/' Because in this project, the front-end and back-end are separate development frameworks. I implemented the back end using Golang. After this back-end is started, it is an independent HTTP server that will occupy the port number. 8888 is my custom listening port number. The interface address of this back-end service can be customized and deployed according to your own project situation, and you can modify the value of the custom constant "serverUrl." After completing the above code, you can use the FaceIO function in the Vue file. For example, in "userLogin. vue", the usage of the facial authentication code is shown below: Vue.js Component window.myFaceIO.authenticate({ "locale": "auto" }).then(userInfo => { checkFaceLogin(userInfo); }).catch(errCode => { console.log(errCode); window.myFaceIO.restartSession(); }) Among them, the function checkFaceLogin() is a custom callback function. It is used to process the user authentication result data returned by FaceIO after authentication. We can proceed with the next step of business logic processing based on the verification result data returned by FaceIO. Take a screenshot of the runtime as shown below: For example, in 'sysDashboard.vue', the usage of facial identity registration codes can be found below: Vue.js Component <script> export default { name: 'sysDashboard', activated() { this.AjaxPost("dashboard","",initData); function initData(result) { if(result.Code===1){ let fid=result.Result.FacialId if(fid.length>4){ document.getElementById("myFacialId").innerHTML=fid document.getElementById("FacialIdReg").disabled=true; } } } }, methods: { faceReg: function() { const that=this window.myFaceIO.enroll({ "locale": "auto" }).then(userInfo => { addFacialAuth(userInfo); }).catch(errCode => { console.log(errCode); }) function addFacialAuth(userInfo) { let obj = {}; obj.FacialId = userInfo.facialId; that.AjaxPost("userEdit",obj,addFacialAuthEnd); } function addFacialAuthEnd(result) { if(result.Code===1){ document.getElementById("myFacialId").innerHTML=result.Result.FacialId document.getElementById("FacialIdReg").disabled=true; }else { alert("add Facial Auth fail") } } } } } </script> Among them, the function faceReg() is a custom facial recognition registration function. The subfunction addFacialAuth() is a custom callback function. It is used to process the user registration result data returned by FaceIO after identity registration is completed. We can use the registration result data returned by FaceIO. Proceed to the next step of business logic processing. Please note the calling method of the custom function AjaxPost() here. It is not directly called using the method of 'this. AjaxPost()'. But in the first line of the function faceReg() JavaScript const that=this Define a constant 'that' before using 'that. AjaxPost()' in the subfunction addFacialAuth(). This is because in the subfunction addFacialAuth(), 'this. AjaxPost()' is invalid. Take a screenshot of the runtime as shown below: How To Integrate FaceIO in Golang’s Back-End In the code of this project, Golang is used to implement back-end services. Golang has good concurrency performance, memory management automation, and other advantages, so it has been widely used in building back-end services. Please install Golang first. In this project code, I am using version 1.13.15. After installing Golang, it is easy to create Golang project files in the Goland development tool. Also, please note one point. In this project, there is no persistent data storage in Golang. The data is all in memory, and if the service is restarted, the data will be initialized. Because this project is a demo, it is just a simple example. Step 1: Create an HTTP Server In the code of this project, an HTTP server is created in the file "api_router. go". Here is the code: Go package routes import ( "../conf" "../handlers" "fmt" "log" "net/http" ) func ApiRouter() { http.HandleFunc("/dashboard", handlers.Dashboard) http.HandleFunc("/config", handlers.Config) http.HandleFunc("/login", handlers.Login) http.HandleFunc("/loginWithFace", handlers.LoginWithFace) http.HandleFunc("/userEdit", handlers.UserEdit) port := conf.GetEnv().ServerPort if port == "" { port = "8080" log.Printf("Defaulting to port %s", port) } log.Printf("Listening on port %s", port) log.Printf("Open http://localhost:%s in the browser", port) log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil)) } In the above code, use the ‘http.HandleFunc()’ function to register multiple router functions into the HTTP multiplexer. These router functions will handle all requests from the client. Finally, call the ‘http.ListenAndServe()’ function to start listening to HTTP requests on the port. When the current end sends a request to the back end, the corresponding router function will be executed, and a response will be returned. Step 2: Receive the Request From the Vue.js Front-End To facilitate code management, I have included all these router functions in the package "handlers." For example, obtaining the public ID of an application registered in FaceIO. The code for this function is in the file "config.go", as shown below: Go package handlers import ( "../conf" "../model" "encoding/json" "io" "net/http" ) func Config(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Headers", "*") result := make(map[string]string) result["FaceIOAppCode"] = conf.GetEnv().FaceIOAppCode jsonResult := new(model.JsonResult) jsonResult.Code = conf.GetEnv().CodeSuccess jsonResult.Msg = conf.GetEnv().MsgSuccess jsonResult.Result = result msg, _ := json.Marshal(jsonResult) _, _ = io.WriteString(w, string(msg)) } Please note that in the above code, there are two lines of code. Go w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Headers", "*") This is the setting that allows cross-domain access. Because in my local development environment, the front-end startup is an independent HTTP server, and the back-end startup is also an independent HTTP server. The data interaction between the front-end and back-end belongs to cross-domain access. If you deploy in a production environment, you may be able to run using an HTTP server. For example, using Nginx, you can set up a reverse proxy. This belongs to the same domain access, so these two lines of code are not required. Because in the code of this project, both the front-end and back-end data interactions use JSON data format. So, in the above code, call the function ‘json.Marshal()’ to format the data. Viewing Application Usage on the FaceIO Console As a facial recognition technology service provider, FaceIO provides many services on its console. For example, facial detection, facial search, facial authentication, live body detection, and so on these functions can be completed by simply calling its provided online JavaScript library. In addition, after you register and log in to its management back-end, you can create different applications and assign multiple public IDs based on your business scenario. There are records of the usage of each application, as shown in the screenshots below: In this article, a brief explanation is provided to introduce how to integrate FaceIO using Vue.js and Golang to implement a facial recognition-based identity authentication system. In the Vue.js environment, FaceIO provides an online JavaScript library for facial detection and recognition. It can directly start the user's computer's camera, send the captured facial photos directly to the FaceIO server for processing, and return the recognition results to the front end. The facial photos taken do not need to go through our application. Through this demonstration project, we can not only learn how to build complete web applications using two different programming languages but also learn how to integrate facial recognition technology to enhance application security and user experience. These skills and knowledge can help us better understand computer science and software development and enhance our professional competitiveness. Through practice, we can better understand the working principle of the code and master some practical skills and best practices. In this process, we can make new friends and colleagues, explore and create more valuable things together. I hope everyone can maintain an attitude of continuous learning and progress, constantly exploring and creating more value.

By jianxiang sun
Conditionals In JavaScript
Conditionals In JavaScript

Conditional statements are used for making decisions based on different conditions. Also, conditionals in JavaScript allow you to execute different blocks of code based on whether a certain condition is true or false. Conditions can be implemented using the following ways: If If Else Else If Switch Ternary operators If Statement This statement shows truthy values used to check if the given conditions are true and then execute the block of code. JavaScript if(condition){ -----block of code which is going to execute----- } Let's understand this with an example. JavaScript let num = 10 if (num > 0) { console.log(num + "is a positive number") } //Output => 10 is a positive number// //In the above example, we set the condition that if the user enters any number greater than 0, then "if" condition got executed and it returns the output.// Else Statement It's the opposite of an If statement. So we will say that, if the If condition is not executed, which will happen when the given condition is false, then the Else statement gets executed. JavaScript if(condition){ -----block of code which is going to execute----- } else { -----block of code which is going to execute----- } Let's take an example and try to understand this. JavaScript //lets say we made a google form for football trails and age limit for the peoples who can apply for this is 16+. Now, If the user enter age more or less than the given age, certain blocks of code gets executed and give response accordingly.// let myAge = 15 if (myAge > 16) { console.log(myAge + " is valid age, you are eligible for trials.") } else { console.log(myAge + " is not a valid age, you are not eligible for the trials .") } //I Hope this clears how "If" and "Else" statements works// Else If This is used for most cases because there are multiple options to select from sometimes. Let's understand this with an example. JavaScript if(condition){ -----block of code which is going to execute----- } else if(condition){ -----block of code which is going to execute----- } else { -----block of code which is going to execute----- } Let's say we found an interesting website, and in order to get the most out of this website, it's asking us to make an account on it. As we are going through the process of making an account, it asks us to set questions and answers in case we lose our password so we can still be able to log in by giving the correct answer to the questions. Now, a few months pass and we want to sign in to that website but we couldn't remember our password, so the website gives us the option to sign in by giving answers to the questions we set previously. It gives us a question and four options to choose from. Que: What is your favorite color? a) blue b) Indigo c) pink d) red JavaScript let favColor = 'blue' if(favColor === 'indigo'){ console.log("indigo is not your favorite color.Try again") } else if(favColor === 'pink'){ console.log("pink is not your favorite color.Try again") } else if(favColor === 'red'){ console.log("Seriously, red, broooo Try again") } else if(favColor === 'blue'){ console.log("Thats my bro, blue is your fav color. Never forget your password again.") } else { console.log("Enter your fav color") } Switch Statement The switch statement is an alternative for If Else statements. The switch statement makes the code more concise and easier to read when you need to test a single variable against multiple possible values. JavaScript switch (case value) { case 1: console.log(' ') break; //Suppose, the condition is satisfied after end of case 1, then, 'break' terminates the code// case 2: console.log(' ') break; default: //default runs only if all the cases dont satisfy conditions.// console.log(' ') } Let's understand this with an example. JavaScript let theDay = 'tuesday' switch(theDay) { case'monday': console.log('Today is not monday'); break; case'tuesday': console.log('Yes, today is tuesday'); break; default: console.log('Please enter a valid day'); } //In this example, the code terminates after 2nd case, as the condition is satisfied at case 2// Ternary Operator It is a simple way of writing an If Else statement. It takes three values or operands: A condition Expression to execute if the condition is true Expression to execute if the condition is false Let's understand this with an example. JavaScript let playFootball = true playFootball ? console.log('you needs football boots to play on ground') : console.log('i dont wanna play') The ternary operator is useful when you need to make a simple decision based on a single condition. It can make your code more concise and easier to read, especially when used with short expressions. Conclusion This blog discusses various conditional statements in JavaScript, which allow the execution of different blocks of code based on certain conditions. This includes If, Else, Else If, Switch, and Ternary operators. If statements are used to check whether a condition is true, while Else statements execute when the If condition is false. Else If statements are used when multiple options need to be considered. Switch statements are an alternative to If Else statements and make the code more concise. Ternary operators are a simple way of writing If Else statements.

By Shashank Sharma
Creating a Portfolio Website Using Bit Components: Step-by-Step Guide
Creating a Portfolio Website Using Bit Components: Step-by-Step Guide

As a developer, you build software that addresses real-world challenges and positively impacts people's lives. Moreover, your work could attract significant interest from your peers and colleagues. And having a portfolio to showcase your skills and expertise would be exciting. Knowing this, I built a simple portfolio website allowing visitors to get to know me and my work! And you can also use it to create a portfolio for yourself. Building My Portfolio Site The Outcome First, let us take a look at the site that we are going to build. Currently, it is deployed in this URL. The site has five main pages: Landing, Projects, Contact, About, and a Detailed Project page. These are shown below. Selecting the Tech Stack and Architecture When I started building my site, I wanted to utilize a tech stack and an architecture that's faster to develop, and anyone could customize to create their portfolio. Therefore, I used React for my front end, with Bit adopting a component-driven architecture. Using Bit, I've split my portfolio application into five main scopes. Here, a scope is like a collaboration server for a collection of components. Design: The design scope holds the design system of the portfolio. It contains components such as the theming and generic elements combined to build feature components. Personal Portfolio: This scope contains the portfolio web application. It holds the application component that is deployed onto Netlify. Dev: The dev scope is created to maintain the development environment and configurations. For example, I've used a custom React 18 environment to ensure all components utilized React 18. Contact Me: The contact me scope was created to separate the contact me logic from the rest of the scopes. It's connected with an API to support form submission. Starters: The starters scope holds the component responsible for building a boilerplate for others to reuse this portfolio. In summary, the scopes are connected as shown below. The high-level scope usage architecture Building the Website: Step-by-Step Guide While developing this application, I followed several best practices in creating Bit components. Let's go through them one by one. Naming scopes: Initially, I used lengthy names such as portfolio-site-design-system as scope names. However, this limits me from reusing the design scope and components with other applications. Hence, I recommend using short, generic, and readable names like design. Naming namespaces: Inside a scope, you'd include several namespaces. For example, I've included several namespaces in the personal-portfolio scope, such as pages, apps and hooks. This makes your code organized and easy to maintain. And, it's often a Bit best practice to use plural nouns as a namespace name. For example, don't use page. Instead, use pages. Naming components: It's essential to understand that you are building independent components which can be built in an isolated environment. Hence, your components should only be aware of each by composition. For example, if you were creating a Button component, ensure that you name the component as Button and not LandingPageButton. Selecting Props: Try to make your component properties as relevant to your component as possible. For example, don't use landingPageVariant. Instead, use variant to toggle the Button variant. You should be able to customize a component without modifying its internal code (open-closed principle). Thus, use prop spreading to bring about complete customizability. One such implementation is shown here. Don't delete components: Do not delete a Bit component after you've exported it. This is because other components may depend on it. Therefore, it is an excellent practice to deprecate your component using bit deprecate. Start with failing test cases: With Bit, you can seamlessly integrate TDD into your development workflow. Every component has a test file that ensures you ship out thoroughly tested code. Therefore, always start developing your component by designing your test cases first. Start writing failing test cases (that reflect your actual output) and implement your component to ensure that your test cases pass. An excellent example of integrating TDD into your development workflow is shown here through the Projects entity component I've implemented. Initializing the Workspace Firstly, you will need a Bit workspace to develop your components. To do so, run the command shown below. bit new react my-workspace --default-scope showoff.design The snippet above will create a new React workspace titled my-workspace and will use a default scope named showoff. Note, you can change this to your preference. This means that out of the box, my components get exported to a scope named "design" in the "showoff" organization in Bit cloud. Run bit start to launch the development server, and run bit create react my-component-name to create a new React component. Next, I can start building my design and application scopes. Building the Design Scope The entire application was built using MUI. Therefore, I've extended the MUI components and provided custom implementations where necessary. For example, I extended the MUI theme to create my own theme component as shown here. import { alpha, Theme, ThemeOptions } from '@mui/material'; import { themeCreator } from '@showoff/design.theme.theme-creator'; import { baseTheme } from '@showoff/design.theme.base-theme'; /** * Function that returns a configured light theme * @param additionalConfigurations - Additional configurations to be applied to the theme * @returns Configured light theme */ export function lightTheme(additionalConfigurations?: ThemeOptions): Theme { return themeCreator( baseTheme(), { palette: { mode: 'light', primary: { main: '#6C5CE7', }, background: { default: '#FFFFFF', paper: '#FFFFFF', }, text: { primary: '#2B2B2B', }, divider: '#BABEC9', }, components: { MuiButton: { defaultProps: { disableRipple: true, disableElevation: true, variant: 'contained', }, styleOverrides: { root: { textTransform: 'none', color: '#FFFFFF', }, sizeSmall: { padding: '6px 16px', }, sizeMedium: { padding: '8px 20px', }, sizeLarge: { padding: '11px 24px', }, textSizeSmall: { padding: '7px 12px', }, textSizeMedium: { padding: '9px 16px', }, textSizeLarge: { padding: '12px 16px', }, }, }, MuiChip: { styleOverrides: { root: { color: '#6C5CE7', fontWeight: 700, height: '24px', borderRadius: '6px', padding: '4px 8px', verticalAlign: 'middle', alignItems: 'center', }, }, }, MuiInputBase: { styleOverrides: { root: { borderRadius: '8px', borderColor: '#EDEDED', }, input: { '&::placeholder': { color: '#707279', }, }, }, }, MuiInputLabel: { styleOverrides: { root: { color: '#707279', }, }, }, MuiToggleButton: { styleOverrides: { root: { borderRadius: '8px', borderColor: '#EDEDED', transition: 'all 0.3s ease', textTransform: 'none', height: '40px', '&.Mui-selected': { backgroundColor: '#6C5CE7', color: '#EDEDED !important', '&:hover': { backgroundColor: alpha('#6C5CE7', 0.8), }, '& .MuiTypography-root': { color: '#EDEDED', }, }, }, }, }, }, typography: { button: { fontWeight: 600, }, allVariants: { color: '#2B2B2B', }, fontFamily: 'CircularXX', }, }, { ...additionalConfigurations } ); } Here, I've created a custom light theme component that utilizes a custom palette. Likewise, I extended the MUI design system to build my design elements, as shown below. Design Scope The design scope contains the design system used for the portfolio site. Next, I implemented the site's navigation menus, layouts, inputs, and even a font family. I have designed these components as separate units, which enables them to be reusable and developed independently. For example, here is the application's main navigation menu that I implemented. The application header The figure above shows a header component that compiles the navigation menu for the application. The reusable and customizable header component allows you to change the links, theme toggle, and brand logo. Building the Developer Scope While developing the site, I noticed all my components had two main compositions: Light and Dark. These compositions utilized the Light and Dark theme in the design scope. By customizing the Bit developer environment tabs (Docs and Composition), I could use a single composition with a toggle button for theme selection. For example, let's look at the react-with-mui environment I developed. Exploring the custom environment The environment component has four main files: docs.tsx - The file that allows you to provide a custom implementation for the Documentation view of Bit mounter.tsx - The file that allows you to provide a custom implementation for the Composition view of Bit env.jsonc - The file that lets you declare the dev, runtime, and peer dependencies that will be used by the components that use the environment my-react-env.bit-env.ts - The file that lets you mount the custom docs, composition implementations to a component Here, I decided to update the docs.tsx and mounter.tsx file to utilize a ThemeToggle component to toggle between the Dark and Light themes for each component as shown below. import React, { useState } from 'react'; import { createMounter } from '@teambit/react.mounter'; import { Box } from '@mui/material'; import { ThemeProvider } from '@showoff/design.theme.theme-provider'; import { ThemeToggle } from '@showoff/design.theme.theme-toggle'; import { darkPortfolioTheme } from '@showoff/personal-portfolio.theme.dark-portfolio-theme'; import { lightPortfolioTheme } from '@showoff/personal-portfolio.theme.light-portfolio-theme'; /** * use the mounter to inject and wrap your component previews * with common needs like [routing](), [theming]() and [data fetching](). */ // eslint-disable-next-line react/prop-types export function MyReactProvider({ children }) { const [themeMode, setThemeMode] = useState<'light' | 'dark'>('light'); return ( <ThemeProvider theme={themeMode === 'dark' ? darkPortfolioTheme() : lightPortfolioTheme()} > <Box sx={{ p: 5 }> <Box sx={{ display: 'flex', justifyContent: 'flex-end' }> <ThemeToggle isDark={themeMode === 'dark'} onClick={() => setThemeMode(themeMode === 'dark' ? 'light' : 'dark')} /> </Box> {children} </Box> </ThemeProvider> ); } /** * to replace that mounter component for different purposes, just return a function * that uses ReactDOM to render a node to a div. */ // @ts-ignore export default createMounter(MyReactProvider) as any; The snippet shown above creates a custom implementation for the Composition view. It uses a Theme Toggle to allow Dark/Light toggling and applies the theme for the children that has been passed. After designing my environment, I had to update my existing components with the new environment. To do so, I executed the command displayed below. bit envs set <<COMPONENT-NAME>> <<ENV-NAME>> Hereafter, I was able to directly utilize theme toggling within the component through the env as shown below. This reduced the composition code in half, just having one composition allowing to toggle between the themes. Building the Application After building the design scope using the custom environments, I created an application component that is deployable to host the entire site. The application component includes all the pages, and the Bit Netlify Deployer is used to deploy the application directly onto Netlify. The application is hosted on the URL linked at the beginning of this post. const { Netlify } = require("@teambit/cloud-providers.deployers.netlify"); const { splitChunks, addSitemap, } = require("@showoff/dev.transformers.portfolio-transformer"); const { prerenderRoutes } = require("./prerender-routes"); const netlifyConfig = { accessToken: process.env.NETLIFY_AUTH_TOKEN, stagingSiteName: "portfolio-showoff-staging", productionSiteName: "portfolio-showoff-production", team: "enlear", redirects: "_redirects", webpackTransformers: [ splitChunks, (config, context) => addSitemap(config, context, [...prerenderRoutes]), ], }; const PortfolioApp = { name: "portfolio", entry: [require.resolve("./portfolio.app-root")], prerender: { routes: ["/"], }, webpackTransformers: [ splitChunks, (config, context) => addSitemap(config, context, [...prerenderRoutes]), ], deploy: Netlify.deploy(netlifyConfig), }; module.exports.default = PortfolioApp; App Component This deployer runs whenever you tag your application component, thus simplifying the entire deployment process. Wrapping Up In this blog post, I've highlighted the most important aspects to consider when building your own. I've also created a Bit Starter, which helps you generate a boilerplate code of the portfolio website, which you can customize to build your portfolio in under 10 minutes. Open up a terminal and execute the command shown below. bit new portfolio portfolio-workspace --aspect showoff.starters/portfolio By doing so, Bit will create a new workspace with the components required to deploy a copy of the portfolio as your own! To explore the complete codebase, look at my GitHub repository or visit my Bit cloud account to inspect the five scopes. I hope that you have found this article helpful. Thank you for reading!

By Lakindu Hewawasam
Cypress JavaScript Tutorial: A Step-By-Step Handbook
Cypress JavaScript Tutorial: A Step-By-Step Handbook

Cypress is a popular end-to-end testing framework used for web applications. It is an open-source JavaScript testing tool designed to make testing web applications fast, easy, and reliable. Cypress allows developers to write automated tests that simulate user interactions and verify the behavior of the applications. We can use Cypress with JavaScript or TypeScript for development, but JavaScript is the primary language used with Cypress. Cypress is built on top of JavaScript and uses many of the same concepts of modern web development, such as using a browser-based environment to run tests and interacting with web elements using CSS Selectors. When writing tests in Cypress, you can use JavaScript to create test cases that simulate user interactions and validate the behavior of your application. Cypress also provides a powerful set of built-in commands and assertions to help you write tests quickly and easily. However, before explaining Cypress JavaScript in detail, we’ll see why we use JavaScript for Cypress test case automation. Why Cypress With JavaScript? There are several reasons why Cypress and JavaScript work well together: Cypress Is Written in JavaScript Cypress is written in JavaScript, so developers who are already familiar with JavaScript will find it easier to work with Cypress. Cypress Has Extensive Support for JS Frameworks Cypress has good support for popular JavaScript frameworks like React, Vue, and Angular. This means that developers building applications using these frameworks can easily write tests for their applications using Cypress. Cypress Has a Rich API for Interacting With Web Applications Cypress provides a rich API for interacting with web applications, which includes methods for interacting with the DOM, making HTTP requests, and handling events. This API is designed to be easy to use and well-documented, making it easy to write tests using JavaScript. Debugging Support Cypress provides a comprehensive debugging experience, including built-in debugging tools and the ability to step through tests. Community Support There is a vast community of JavaScript developers, which means that plenty of resources are available online to help developers with any issues they encounter while using Cypress. Cypress uses a unique architecture that enables it to run tests in the same context as the application being tested. This means that Cypress has access to the application's DOM, network traffic, and even its backend server. This architecture allows for faster and more reliable tests and a more intuitive and powerful testing experience. Trends of Cypress on GitHub The data below is gathered from the official site of Cypress GitHub repository: Stars: 43.1k Forks: 2.8k Used By: 769k Releases: 302 Contributors: 435 Benefits of Using Cypress JavaScript for Automation Cypress JavaScript provides several features that make it easy to write and run tests, debug issues, and ensure the quality of web applications. We'll explore some of the key features of the Cypress automation tool in detail. Easy Setup Cypress JavaScript is very easy to set up and use. It can be easily installed with npm and requires minimal setup. Cypress also comes with a user-friendly graphical interface, which makes it easy for developers to navigate and use. Comprehensive APIs Cypress JavaScript provides a rich set of APIs for interacting with the DOM, making HTTP requests, and more. This makes it easy to write tests that simulate user interactions with your web application. Real-Time Reloads Cypress JavaScript provides real-time reloads, which means that any changes made to the code or tests are instantly reflected in the browser. This saves developers time and makes it easy to see the impact of changes in real-time. Automatic Waiting Cypress JavaScript automatically waits for assertions to pass and for elements to appear before executing the next command. This makes tests more stable and reduces the likelihood of false negatives. Debugging Cypress JavaScript comes with built-in debugging tools, making it easy to troubleshoot and fix failing tests. Developers can use these tools to inspect the DOM, debug JavaScript code, and more. Time Travel Cypress JavaScript provides a unique feature called "time travel" that allows you to go back and forth in time, inspecting and debugging your application at any point in the test. This feature can save developers a lot of time and effort when trying to debug complex test scenarios. Cross-Browser Testing Cypress JavaScript supports cross-browser testing and can run tests on different browsers. This makes it easy to ensure that your application works as expected across different browsers. Automatic Screenshots and Video Cypress JavaScript can automatically take screenshots and record videos of your tests, making it easy to see what happened during a test run. This can be helpful when trying to identify issues or bugs in your application. Custom Commands Cypress JavaScript allows developers to create custom commands that can be reused across different tests. This makes it easy to create a library of common test commands and reduces the amount of code duplication. Continuous Integration Cypress JavaScript can be easily integrated with popular continuous integration (CI) tools like Jenkins, CircleCI, and Travis CI. This makes it easy to run tests automatically as part of your CI/CD pipeline. How To Install and Set up Cypress Cypress end-to-end testing framework is easy to set up and use. Here are the steps to install and set up Cypress. 1. Install Node.js Cypress requires Node.js to be installed on your system. You can download and install the latest version of Node.js from the official website https://nodejs.org. 2. Create a New Project Create a new directory for your Cypress project and navigate into it using the command line. Run npm init to create a package.json file. 3. Install Cypress Install Cypress by running the following command in the command line. npm install cypress --save-devHere --save-dev is a command-line option used with Node Package Manager (npm) to install and save development dependencies for a project.ORyarn add cypress --devHere, we can see version 12.6.0 installed. Save it as a development dependency in your package.json file. Open Cypress Once installed, you can open Cypress by running the following command in the command line. yarn run cypress open The default folder structure of Cypress is shown below. You can create test cases under the folder “e2e”. Project Structure of Cypress From the screenshots, you can see that Cypress has created a default folder hierarchy when it opens for the first time. Below are the details for each of these folders/files created by Cypress. Cypress: This is the main folder for your Cypress project. It contains all the subfolders and files related to your tests. e2e: This is the main folder to store all your tests. We can add the Basic, End to End Test, API, Visual or Cucumber test here. All your spec files will be here. fixtures: The fixtures/folder is where you can store static data files, such as JSON or CSV files, which your tests can use. For example, you may have a fixture file containing a list of test data that multiple test cases can use. support: This folder contains reusable test code that can be shared across multiple test specs. This can include custom Cypress commands, page objects, or utility functions. There are two files inside the support folder: commands.js and index.js. command.js: This is the file where you add your commonly used functions and custom commands. It includes the common functions that you may call to use in different tests. Cypress created some functions for you, and you can override them here if you want. e2e.js: This file runs before every single spec file. In this file, we keep all global configurations and can modify them as per the requirement. By default, it imports only commands.js, but you can import or require other files to keep things organized. node_modules: All the node packages will be installed in the node_modules directory and available in all the test files. So, in a nutshell, this is the folder where NPM installs all the project dependencies. cypress.config.js: This is a configuration file used by the Cyprestesting framework to customize the behavior of the framework and tests. This file can be used to configure various settings for your tests, such as the base URL for your application, viewport size, test timeout values, and other options. The cypress.config.js file is located in the root of the Cypress project, alongside the cypress folder. When Cypress runs, it will automatically load this file and use the configuration values specified in it. Apart from the above folders, we have some more folders like Screenshots, Downloads, and Videos to store different related files. Basic Constructs of Cypress Cypress uses the same syntax as Mocha for writing test cases. The following are some of the key constructs frequently used in Cypress test development. describe(): This method is used to group related test cases. It takes two arguments: a string that describes the group of test cases and a callback function that contains the individual test cases. it(): This method is used to define a test case. It takes two arguments: a string that describes the test case and a callback function that contains the actual test code before(): This method is used to run a setup function before any test case in a particularly described block. It can be used to set up the test environment, initialize variables, and perform other setup tasks. after(): This method is used to run a cleanup function after all the test cases in a particularly described block have finished running. It can be used to clean up the test environment, close open connections, and perform other cleanup tasks. beforeEach():This method is used to run a setup function before each test case in a particularly described block. It can be used to reset the state of the test environment and perform other setup tasks. afterEach(): This method is used to run a cleanup function after each test case in a particularly described block has finished running. It can be used to reset the state of the test environment and perform other cleanup tasks. .skip(): When dealing with a large codebase and wanting to concentrate on specific tests or subsets of tests, the .skip() function provides a handy means to temporarily prevent certain tests from being executed. Types of Testing Performed Using Cypress JavaScript Cypress is a JavaScript-based testing framework that provides a comprehensive set of features for testing different aspects of web applications, including UI, API, mobile responsiveness, and accessibility. Here's how Cypress JavaScript can be used for each of these types of testing: User Interface (UI) Testing Cypress allows easy and comprehensive UI testing. Cypress provides APIs that allow developers and testers to interact with the web application's UI elements and simulate user interactions while performing Cypress UI automation. The Cypress APIs are capable of validating the application's functionality by allowing users to click on buttons, enter data into forms, and navigate between different pages. It also provides an automatic waiting mechanism that waits for the UI to finish rendering, ensuring that the tests are accurate, reliable, and less flaky. Cypress JavaScript offers significant benefits in dealing with flakiness due to its ability to automatically retry failed tests and provide reloading in real-time. Application Programming Interface (API) Testing Cypress can also be used to test the web application's APIs. Testers can use Cypress to send HTTP requests and validate the responses. It provides a built-in command called cy.request() that enables testers to send HTTP requests and make assertions based on the received responses while performing Cypress API testing. Additionally, Cypress JavaScript supports response interception, mocking, and stubbing, allowing testers to simulate different server responses. Accessibility Testing Cypress can be used to test the accessibility of the web application. Cypress JavaScript provides an integrated accessibility testing library called cypress-axe, which uses the Axe engine to detect accessibility issues and generate accessibility violation reports. With Cypress accessibility testing, it's possible to test the web application's accessibility features and ensure that it's usable by everyone, regardless of any disabilities. Component Testing Cypress is also suitable for component testing, which is useful when working with a modular application that utilizes several components. Cypress JavaScript offers an isolated test environment, making it easy to test individual components and ensure that they work as expected. This testing approach helps to identify and resolve issues early in the development process, reducing the chances of the web application crashing. Mobile Responsiveness Testing Cypress can be used for web application responsive testing across different viewports. Cypress provides a viewport resizing feature, allowing testers to simulate mobile devices' different screen sizes, making it easy to test the web application's responsiveness. Additionally, Cypress JavaScript can integrate with third-party mobile testing platforms like LambdaTest, which offers access to a vast range of mobile devices and operating systems. UI Testing With Cypress JavaScript Cypress provides easy access to the application's DOM, making it easy to manipulate and assert the state of individual elements on the page. It also supports plugins, which can be used to extend its functionality and integrate with other tools and services. These are the reasons Cypress JavaScript is preferred for UI testing. UI Test Case: Example 1 Let’s create a new folder under the e2e folder named “LambdaTest” to perform Cypress UI testing. Create the first spec with the name LoginWithValid_Invalid_Data.cy.js under the folder LambdaTest. In the below test case, we are covering login into LambdaTest with Valid/Invalid data. For demo purposes, we are using the LambdaTest eCommerce Playground site. Use Case Login into the application and update the newsletter subscription JavaScript describe('Login and Subscribe', () => { it('Logs in and subscribes to newsletter', () => { // Visit the site cy.visit('https://ecommerce-playground.lambdatest.io/index.php?route=account/login') // Click the login button cy.get('[value="Login"]').click() // Enter valid email and password cy.get('#input-email').type('lambdatestnew@yopmail.com') cy.get('#input-password').type('Lambda123') // Click the login button cy.get('[value="Login"]').click() // Verify successful login cy.url().should('include', 'index.php?route=account/account') cy.contains('My Account').should('be.visible') // Subscribe to newsletter cy.contains('Newsletter').click() cy.get('#input-newsletter-yes').click({force:true}) cy.get('[value="Continue"]').click() // Wait for subscription success message cy.get('.alert-success').should('contain', 'Success: Your newsletter subscription has been successfully updated!') }) }) Output Below is the output of the above-executed test case. UI Test Case: Example 2 Create the second spec with the name SerachWithValid_InvalidData.cy.js under the folder LambdaTest. In the below test case, we are covering the search with valid and invalid data and verifying the search result. JavaScript describe('Search with Valid/ Invalid data' , () => { beforeEach(() => { cy.visit('https://ecommerce-playground.lambdatest.io/index.php?route=account/login') }) it('Searches for the text "Apple" and displays results', () => { // Enter search data and submit form cy.get('[name="search"]').eq(0).type('Apple') cy.get('.type-text').click() // Verify search results cy.url().should('include', 'search=Apple') cy.contains('Search - Apple').should('be.visible') cy.get('.product-layout').should('have.length.gt', 0) }) it('Displays message with no search results for invalid search term', () => { // Enter search term that returns no results and submit form cy.get('[name="search"]').eq(0).type('abc') cy.get('.type-text').click() // Verify message for no search results cy.contains('There is no product that matches the search criteria.').should('be.visible') }) }) Output Below is the output of the above-executed test case. API Testing with Cypress JavaScript Developers and testers using Cypress can create tests that send HTTP requests to their application's API and validate the corresponding responses. We can use Cypress API to write automated tests that simulate user interactions with the application's API endpoints. This type of testing is especially useful for testing API responses, validating data input and output, and verifying the application’s behavior. It also provides several built-in assertions that can be used to verify the response status code, headers, and body. Here are some key features of using Cypress JavaScript for API testing: HTTP Requests Cypress provides simple and intuitive APIs for making HTTP requests, allowing developers to test different API endpoints and parameters easily. It supports all common HTTP methods, such as GET, POST, PUT, DELETE, etc. Mocking and Stubbing Cypress lets you mock and stub API responses, which is useful when testing API endpoints that rely on third-party services or data sources that may not be available during development/testing. Request and Response Objects Cypress provides request and response objects that allow developers to inspect and manipulate the data being sent and received by APIs. This can help test complex APIs with nested data structures. Authentication and Authorization Cypress supports testing APIs that require authentication or authorization. Testers can use the built-in cy.request method to send authentication tokens or cookies, or they can use plugins to integrate with external services such as OAuth providers. Built-In Support for GraphQL Cypress provides built-in support for testing GraphQL APIs, including a GraphQL-request method that simplifies making GraphQL queries. API Automation Examples For API testing demo purposes, we are taking the example of the site. In the below API testing example, we are covering CRUD operation using the REST API. API Test Case: Example 1 GET Request The GET method is used to retrieve specific data and pass parameters on reading code from the API response. In the example below, we are getting specific user data using the GET method and userId. JavaScript it('GET API Automation Using GoRest API', () => { cy.request({ method: 'GET', url: 'https://gorest.co.in/public/v1'+`/users/${userId}`, headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, }).then((response) => { expect(response.status).to.equal(200); expect(response.body.data.name).to.equal('John Doe'); expect(response.body.data.gender).to.equal('male'); }); }); Output Below is an example of a POST request along with a bearer token for authorization. In POST requests, we retrieve userId for further use by passing data in the body. POST Request JavaScript describe('API Automation Using GoRest API', () => { let randomNumber =Math.floor(Math.random() * 1000); let userId; it('POST API Automation Using GoRest API', () => { const user = { name: 'John Doe', email: "johndoe123"+randomNumber+"@example.com", gender: 'male', status: 'active', }; cy.request({ method: 'POST', url: 'https://gorest.co.in/public/v1/users', headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, body: user, }).then((response) => { userId=response.body.data.id expect(response.status).to.equal(201); expect(response.body.data.name).to.equal(user.name); expect(response.body.data.email).to.equal(user.email); }); }) }); Output PUT Request Below is an example of a PUT request and a bearer token for authorization. In PUT requests, we update the existing data by passing the userId for which we want to update the data. JavaScript it('PUT API Automation Using GoRest API', () => { const user = { name: 'Time Cook', email: "TimCook123"+randomNumber+"@example.com", gender: 'male', status: 'active', }; cy.request({ method: 'PUT', url: 'https://gorest.co.in/public/v1'+`/users/${userId}`, headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, body: user, }).then((response) => { expect(response.status).to.equal(200); expect(response.body.data.name).to.equal(user.name); expect(response.body.data.email).to.equal(user.email); }); }); Output DELETE Request The created record can be deleted using the delete method. We can pass the userId and an authorization token in the header. JavaScript it('DELETE API Automation Using GoRest API', () => { cy.request({ method: 'DELETE', url: 'https://gorest.co.in/public/v1'+`/users/${userId}`, headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, }).then((response) => { expect(response.status).to.equal(204); }); }); Output API Automation Using ‘Cypress-Plugin-Api’ Plugin The 'cypress-plugin-api' is a useful plugin for Cypress that provides a simplified and streamlined API for making HTTP requests and performing API testing in your Cypress tests. There are several benefits of using this plugin, some of which are listed below. cy.api() command informs about the API call, such as URL, headers, response, and more to the UI frame, and this info can be viewed in time-travel snapshots. Simple table for viewing cookies. JSON data object and array folding. Color coding of methods in UI view and in the timeline. Let’s set up cypress-plugin-api. Steps 1 Install the plugin 'cypress-plugin-api' using the below commands. npm i cypress-plugin-api Or yarn add cypress-plugin-api Steps 2 Import the plugin under the path cypress/support/e2e.js file. import 'cypress-plugin-api' or require('cypress-plugin-api') package.json looks like below: JavaScript { "name": "cypress_javascript", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Kailash Pathak", "license": "ISC", "devDependencies": { "cypress": "^12.6.0" }, "dependencies": { "cypress-plugin-api": "^2.10.3" } } Add the below commands under the Cypress/e2e.js file are below: import './commands' import 'cypress-plugin-api' Let's take some examples to automate using the plugin cypress-plugin-api. Create ApiTestCaseUsingPlugin.cy.js with Methods (GET, POST, PUT, DELETE) Below is an example of Methods (GET, POST, PUT, DELETE) with their output of the execution of Test Cases. The data for Body, Response, Headers, and Cookies may be seen in the Cypress App UI in the screenshot below. The cy.api() works similarly to the cy.request() command. The benefit of using cy.api() is it provides the response, headers, and cookies are all visible, and also prints details about the call in your Cypress runner, as shown below. GET Request JavaScript it('GET API Automation Using GoRest API', () => { cy.api({ method: 'GET', url: 'https://gorest.co.in/public/v1'+`/users/${userId}`, headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, }).then((response) => { expect(response.status).to.equal(200); expect(response.body.data.name).to.equal('John Doe'); expect(response.body.data.gender).to.equal('male'); }); }); Output GET Request POST Request JavaScript it('POST API Automation Using GoRest API', () => { const user = { name: 'John Doe', email: "johndoe123"+randomNumber+"@example.com", gender: 'male', status: 'active', }; cy.request({ method: 'POST', url: 'https://gorest.co.in/public/v1/users', headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, body: user, }).then((response) => { userId=response.body.data.id expect(response.status).to.equal(201); expect(response.body.data.name).to.equal(user.name); expect(response.body.data.email).to.equal(user.email); }); }); Output POST Request PUT Request JavaScript it('PUT API Automation Using GoRest API', () => { const user = { name: 'Time Cook', email: "TimCook123"+randomNumber+"@example.com", gender: 'male', status: 'active', }; cy.request({ method: 'PUT', url: 'https://gorest.co.in/public/v1'+`/users/${userId}`, headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, body: user, }).then((response) => { expect(response.status).to.equal(200); expect(response.body.data.name).to.equal(user.name); expect(response.body.data.email).to.equal(user.email); }); }); Output PUT Request DELETE Request JavaScript it('DELETE API Automation Using GoRest API', () => { cy.request({ method: 'DELETE', url: 'https://gorest.co.in/public/v1'+`/users/${userId}`, headers: { Authorization: 'Bearer 84bb7773414ee1a1247f6830428a2ab051d763d7cb24c97583f10ca96a59ddde', }, }).then((response) => { expect(response.status).to.equal(204); }); }); Output DELETE Request Accessibility Testing With Cypress JavaScript Accessibility testing is the process of evaluating a website or application to ensure that it can be used by people with disabilities. Cypress JavaScript provides an accessibility plugin called cypress-axe that can be used to check for accessibility issues on a website. The plugin employs the axe-core open-source library to conduct accessibility assessments, which detect accessibility infractions under the Web Content Accessibility Guidelines (WCAG). To use the cypress-axe plugin, you first need to install it using npm. Once installed, you can import the plugin into your Cypress test file and use the cy.checkA11y() method to check for accessibility violations. Executing this command triggers the axe-core library to scan the present page and disclose any accessibility problems it detects. Install the Cypress accessibility plugin by running the following command in your project directory: npm install --save-dev cypress-axe Once the installation is complete, you can import the plugin in your Cypress test file by adding the following line at the top: import 'cypress-axe'; Now, you can write your accessibility tests using the cy.injectAxe() and cy.checkA11y() commands provided by the plugin. JavaScript describe('Accessibility testing with cypress-axe', () => { it('should not have any accessibility violations', () => { cy.visit('https://ecommerce-playground.lambdatest.io/'); cy.injectAxe(); cy.checkA11y(); }); }); This test uses the cy.visit() command to open the website, and the cy.injectAxe() command to inject the accessibility plugin. The cy.checkA11y() command then checks the page for accessibility violations. Output In the screenshot, you can see nine accessibility violations. Component Testing With Cypress JavaScript Component testing is a type of software testing in which individual components of a software system are tested in isolation from the rest of the system. What Is Component Testing? The purpose of component testing is to validate the functionality and behavior of individual software modules, such as functions, classes, or methods, to ensure that they work as expected and meet the requirements specified in the design. Component testing primarily aims to uncover flaws or glitches in the software modules before their integration into the broader system, thereby minimizing the likelihood of downstream breakdowns and simplifying the process of isolating and remedying issues. By testing each component in isolation, developers can gain confidence that each module is working correctly, which can improve overall system quality and reduce the time and cost of testing and debugging. Cypress for Component Testing With Cypress, you can use its built-in testing API to create tests that target specific components of your application. Cypress JavaScript provides a <mount> command that can be used to mount a React component within a Cypress test runner, making it possible to test the component's behavior and interactions with other components. Advantages of Component Testing With Cypress JavaScript Early Detection of Defects Component testing helps detect defects or issues in the software code early in the development process. By identifying and fixing issues early, it becomes easier and cheaper to fix them than when they are detected later in the software development life cycle. Improved Reusability Component testing promotes code reusability since individual components can be reused in other applications. Faster Development Component testing helps to speed up the development process. By catching defects early, developers can fix them quickly, which leads to faster development cycles and quicker delivery of software. Better Maintainability Component testing helps to improve the maintainability of the software code. By ensuring that each component of the software is functioning correctly, it becomes easier to maintain the software in the long run. Isolation Since each component is tested in isolation, defects can be easily isolated and identified, making it easier to fix them. Example of Component Testing Before taking the example, let's do some prerequisite steps for creating component testing. Prerequisite Node is installed. VS Code is installed. Testing React components with Cypress involves setting up a testing environment and writing test cases to ensure that the components behave as expected. Here are the steps to get started: Let’s set up a React component. Step 1: Run the below command in the terminal. npx create-react-app my-new-sample-app Step 2: In the root directory and run the below command to launch React app and install Cypress (if not installed previously). cd my-new-sample-app npm start npm install cypress -D Step 3: Run the command to open Cypress runner. npx cypress open or yarn cypress open Step 4: From the below screenshot select ‘Component Testing”. Step 5: After selecting ‘Component Testing’ from the above, the below-attached screen gets opened. Select the option ‘Create React App’ from the above screen. Step 6: Click on Next step from the above screen and wait for all dependencies to install. Step 7: Click on Continue button from the above screen. Step 8: Click on Continue button from the above screen. Select the browser, e.g., Chrome, and click ‘Start Component Testing in Chrome.’ Step 9: Select ‘Create new spec’ and enter the path of the new spec and click ‘Create spec.’ Step 10: Click on Okay, run the spec button. Below is the folder structure after installing the React app. In this structure, the src folder contains all the source code for the project, while the components subfolder is where the component files are stored, and it is from these files that the test files in the components folder at the top level of the project will import the components to be tested. Each component has its folder, which includes the component file itself (component1.js, component2.js, etc.) and its corresponding test file, e.g. (component 1.test.js, component 2.test.js, etc.). Let’s create a component test case. Create a ‘counter component’ inside the src folder and give its name lambadaTest.jsx. JavaScript import { useState } from 'react' export default function Counter({ initial = 0 }) { const [count, setCount] = useState(initial) return ( <div style={{ padding: 30 }> <button style={{ color: "black", backgroundColor: "green", margin: 10 } aria-label="decrement" onClick={() => setCount(count - 1)}> - </button> <span data-cy="counter">{count}</span> <button style={{ color: "black", backgroundColor: "green", margin: 10 } aria-label="increment" onClick={() => setCount(count + 1)}> + </button> </div> ) } Let's run the created component test cases by running the below command. npx cypress open --component In the below screenshot, we can see that component tests are executed. Let’s cover some more scenarios using this Counter React component. Test Scenario Click on (+) to increment the count. Click on (-) to decrement the count. JavaScript import Counter from '../../src/lambadaTest' describe("<Counter>", () => { const counterSelector = '[data-cy="counter"]'; const incrementSelector = "[aria-label=increment]"; const decrementSelector = "[aria-label=decrement]"; it("Do two time increment then one time decrement the count ", () => { cy.mount(<Counter />); //Do two time Increment the Count cy.get(incrementSelector).click(); cy.get(incrementSelector).click(); // Put Assert cy.get(counterSelector).should("contain.text", 2); //Do the decrement now cy.get(decrementSelector).click(); // Put Assert cy.get(counterSelector).should("have.text", "1"); // Put Assert color cy.get(decrementSelector) .should("have.css", "color") .and("eq", "rgb(0, 0, 0)"); // Assert background color cy.get(decrementSelector) .should("have.css", "background-color") .and("eq", "rgb(0, 128, 0)"); }); it("Do two time decrement then one time increment the count ", () => { cy.mount(<Counter />); //Two time decrement the count cy.get(decrementSelector).click(); cy.get(decrementSelector).click(); // Assert cy.get(counterSelector).should("have.text", "-2"); //Then increment the count cy.get(incrementSelector).click(); cy.get(counterSelector).should("have.text", "-1"); // Put Assert color cy.get(decrementSelector) .should("have.css", "color") .and("eq", "rgb(0, 0, 0)"); // Put Assert background color cy.get(decrementSelector) .should("have.css", "background-color") .and("eq", "rgb(0, 128, 0)"); }); }); Output Scenario 1 In the log, first, we increment the count two times and then decrement the count once. Scenario 2 In the log, first, we decrement the count two times and then increment the count once. Mobile Responsiveness Testing With Cypress JavaScript Cypress mobile responsiveness testing is a type of testing that focuses on evaluating the responsiveness and compatibility of a website. It involves using Cypress, an end-to-end testing framework, to automate the process of simulating mobile device interactions and testing the behavior of a website or application across different screen sizes and resolutions. In Cypress JavaScript, the cy.viewport() method is used to set the dimensions of the browser's viewport. Here are some of the different methods that can be used with cy.viewport() to modify the viewport. cy.viewport() with fixed dimensions As mentioned earlier, the cy.viewport() method takes two arguments, width and height, to set the viewport dimensions. For example: cy.viewport(1280, 720) // set viewport to 1280 x 720 pixels cy.viewport() with predefined device Cypress provides several predefined device sizes that can be used with cy.viewport() to simulate different devices. For example: cy.viewport('iphone-6') // set viewport to iPhone 6 size (375 x 667 pixels) cy.viewport('ipad-mini') // set viewport to iPad Mini size (768 x 1024 pixels) cy.viewport() with custom device sizes Developers can also define custom device sizes using the cy.viewport() method. For example: cy.viewport(550, 750) // set viewport to custom size (550 x 750 pixels) cy.viewport() with landscape orientation To simulate landscape orientation, a third argument can be added to cy.viewport(). For example: cy.viewport(1024, 768, 'landscape') // set viewport to 1024 x 768 pixels in landscape orientation cy.viewport() with dynamic sizing Cypress also provides the ability to dynamically set the viewport size based on the screen size of the device running the test. For example: cy.viewport('macbook-15') // set viewport to MacBook Pro 15-inch size on a desktop computer Mobile Responsiveness Test Case Example In the below example, we are using the LambdaTest eCommerce Playground for mobile responsiveness testing. Mobile Responsiveness: Example 1 In this example, we verify that the email and password fields are visible and the label of the email and password fields. JavaScript describe('Mobile Responsiveness Testing', () => { it('Loads the login page in iphone-6', () => { cy.viewport('iphone-6') // set viewport to iPhone 6 size cy.visit('https://ecommerce-playground.lambdatest.io/index.php?route=account/login') cy.get('#input-email').should('be.visible') // check that email input is still visible cy.get('#input-password').should('be.visible') // check that password input is still visible cy.get('input[type="submit"]').should('be.visible') // check that login button is still visible cy.get('label[for="input-email"]').should('have.text', 'E-Mail Address') // check that label for email input is visible and has correct text cy.get('label[for="input-password"]').should('have.text', 'Password') // check that label for password input is visible and has correct text }) }) Code Walkthrough This code uses the viewport command to set the size of the browser window to different mobile device sizes. Then it uses the Cypress get command to check that certain elements on the page are visible and have the correct text. You can check additional tests to check other aspects of the page's responsiveness, such as how images or text scale at different screen sizes. Presented here is an instance of mobile responsiveness testing carried out on an iPhone 6. Similarly, responsiveness testing can be performed on other viewports by modifying the device name in the cy.viewport() method. Output Below is the output of the above-executed test case. Mobile Responsiveness: Example 2 Below is an example for searching the text in the LambdaTest eCommerce Playground for mobile responsiveness testing. Code Walkthrough This code uses the viewport (iphone-x) in beforeEach() hook. In the test case, we are searching the text ‘Apple’ and verify the text after searching. beforeEach() is a hook that runs a block of code before each test case within a test suite. JavaScript describe.only('Mobile Responsiveness Test for search the text in E-commerce Playground Site', () => { beforeEach(() => { cy.viewport('iphone-x') cy.visit('https://ecommerce-playground.lambdatest.io/') }) it('Searches for the text "Apple" and displays results', () => { // Enter search data and submit form cy.get('[name="search"]').eq(1).click({force: true}).type('Apple') cy.get('.type-icon').click() // Verify search results cy.url().should('include', 'search=Apple') cy.contains('Search - Apple').should('be.visible') cy.get('.product-layout').should('have.length.gt', 0) }) }) Output Below is the output of the above-executed test case. Running Cypress Test Cases Locally You can run the test case from the command line or use Cypress runner. Let’s run test cases using Cypress runner. To open the Cypress test runner, run the following command. yarn run cypress open The above command will open the Cypress test runner with the existing test cases. You can select the browser on which you want to run the test case. Let’s execute three test cases in the local environment. LoginAndSubscribeForNewsletter.cy.js, MobileResponsivenessTesting.cy.js, and SearchWithValid_InvalidData.cy.js File Name: LoginAndSubscribeForNewsletter.cy.js JavaScript describe('Login and Subscribe', () => { it('Logs in and subscribes to newsletter', () => { // Visit the site cy.visit('https://ecommerce-playground.lambdatest.io/index.php?route=account/login') // Click the login button cy.get('[value="Login"]').click() // Enter valid email and password cy.get('#input-email').type('lambdatestnew@yopmail.com') cy.get('#input-password').type('Lambda123') // Click the login button cy.get('[value="Login"]').click() // Verify successful login cy.url().should('include', 'index.php?route=account/account') cy.contains('My Account').should('be.visible') // Subscribe to newsletter cy.contains('Newsletter').click() cy.get('#input-newsletter-yes').click({force:true}) cy.get('[value="Continue"]').click() // Wait for subscription success message cy.get('.alert-success').should('contain', 'Success: Your newsletter subscription has been successfully updated!') }) }) File Name: MobileResponsivenessTesting.cy.js describe('Mobile Responsiveness Testing', () => { it('Loads the login page in iphone-6', () => { cy.viewport('iphone-6') // set viewport to iPhone 6 size cy.visit('https://ecommerce-playground.lambdatest.io/index.php?route=account/login') cy.get('#input-email').should('be.visible') // check that email input is still visible cy.get('#input-password').should('be.visible') // check that password input is still visible cy.get('input[type="submit"]').should('be.visible') // check that login button is still visible cy.get('label[for="input-email"]').should('have.text', 'E-Mail Address') // check that label for email input is visible and has correct text cy.get('label[for="input-password"]').should('have.text', 'Password') // check that label for password input is visible and has correct text }) File Name: SearchWithValid_InvalidData.cy.js describe('Login Test', () => { beforeEach(() => { cy.visit('https://ecommerce-playground.lambdatest.io/index.php?route=account/login') }) it('Searches for the text "Apple" and verify result', () => { // Enter search data and submit form cy.get('[name="search"]').eq(0).type('Apple') cy.get('.type-text').click() // Verify search results cy.url().should('include', 'search=Apple') cy.contains('Search - Apple').should('be.visible') cy.get('.product-layout').should('have.length.gt', 0) }) it('Displays message with no search results for invalid search term', () => { // Enter search term that returns no results and submit form cy.get('[name="search"]').eq(0).type('abc') cy.get('.type-text').click() // Verify message for no search results cy.contains('There is no product that matches the search criteria.').should('be.visible') }) }) Let's execute the above test cases. When we run the command yarn run cypress open, the below screen is opened. Test Execution LoginAndSubscribeForNewsletter.cy.js MobileResponsivenessTesting.cy.js SearchWithValid_InvalidData.cy.js Wrapping Up In conclusion, Cypress test automation using JavaScript can significantly improve the speed and efficiency of software testing. As JavaScript supports many testing frameworks, developers can leverage it. Also, JavaScript is very easy to learn. Developers can learn JavaScript very fast and start development.

By Kailash Pathak
Creating a Choropleth Map With JavaScript
Creating a Choropleth Map With JavaScript

Are you ready to learn how to create a choropleth map with JavaScript like a boss? Maps are a powerful way to visualize data, but building one from scratch can be a daunting task. Don't worry, I'm here to help! In this tutorial, I'll guide you through the process of building a JavaScript choropleth map step by step. And to make things more interesting, we’ll use Queen Elizabeth II's state visits as an example to showcase the power of this type of map. Get ready to impress yourself and your audience with stunning data visualizations, and let's get started on this exciting journey together! What Is a Choropleth Map? A choropleth map is a type of thematic map that uses color to represent values of a specific quantity within different regions or geopolitical areas. The map is divided into areas or polygons, and the color of each area represents the value of the data being visualized. Typically, darker shades of color indicate higher values, while lighter shades represent lower values. So, as I mentioned, in this tutorial, we'll be creating a JS-based choropleth map to showcase Queen Elizabeth II's state visits around the world. By using different colors to represent the number of visits in each region, we can easily identify which areas the Queen visited the most frequently. The final interactive choropleth map will look like this: How To Build a Basic Choropleth Map Creating a choropleth map with JavaScript may seem challenging, but fear not! There are just four simple steps to follow: Set up an HTML page to display the map. Add all the necessary JavaScript files. Include the data. Write the required JavaScript code to render the map. Once you've completed these four steps, you'll have a beautiful choropleth map that accurately represents your data. So, let's dive into each step in more detail and learn how to easily create a stunning JavaScript choropleth map! 1. Set up an HTML Page To Display the Choropleth Map To start creating the choropleth map, the first step is to set up an HTML page with a div element and give it a unique ID to reference it later. I’ll set the width and height of the div element to 100% to render the map on the whole page, but you can adjust these values to suit your needs. This div element will be the container for the chart, and the ID will be used to reference it in the JavaScript code. So, let's get started by creating the HTML page for the upcoming choropleth map! HTML <html> <head> <title>JavaScript Choropleth Map</title> <style type="text/css"> html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="container"></div> </body> </html> 2. Add All the Necessary JavaScript Files To easily create data visualizations for the web, I use a JavaScript charting library with in-built utilities and functions. With the vast number of such JS libraries available, the process for creating charts and maps is similar in essence and logic across most of them. In this tutorial, I am using the AnyChart JS charting library as it is beginner-friendly, with extensive documentation and plenty of examples to help you get started. It is needed to link the required JS scripts in the <head> section of the HTML page. These scripts include the Core and Geo Maps modules and the file that contains geodata for the world map, all of which are available on the CDN. I'll also use two more script files to connect the data to the choropleth map. One is the Data Adapter, which will help load the data, and the other is Proj4js, a JavaScript library that will transform the coordinates from one coordinate system to another so the data can be plotted on the map accurately. HTML <html> <head> <title>JavaScript Choropleth Map</title> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-base.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-map.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/geodata/custom/world/world.js"></script> <style type="text/css"> html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="container"></div> <script> // All the code for the JS choropleth map will come here </script> </body> </html> 3. Include the Data Alright, let's get the data loaded up and plotted on the JS choropleth map! First things first, I have collected the data on the state visits made by Queen Elizabeth II from Wikipedia and put it in a JSON file for easy access. You can find it here. All the necessary files are already linked in the <head> section of the HTML page. So it’s possible to use the loadJsonFile() method inside a <script> tag in the body of the page to load the JSON file containing the Queen's state visits data. JavaScript anychart.data.loadJsonFile(<fileURL>, function (data) {}); Great! Now that everything is set up and ready to go, it's time to move on to the main part of the journey: creating the choropleth map visualization! Let's do this! 4. Write the Required JavaScript Code To Render the Map You can get the choropleth map rendered with just a few lines of JS code. First, make sure that all the code is inside the function anychart.onDocumentReady() so that the page is fully loaded before executing anything else. Once the data file is loaded, set the data, create the map, and set the geodata. JavaScript <script> anychart.onDocumentReady(function() { // load data from a json file anychart.data.loadJsonFile('https://gist.githubusercontent.com/shacheeswadia/8f45da54d9bf2032fee201dbfc79e0e4/raw/5d10d58f40b4a1d994cef36dbc64545ef90ead80/queenVisits.json', function (data) { // create a dataset let dataSet = anychart.data.set(data); // create a map instance let map = anychart.map(); // set the geodata map.geoData("anychart.maps.world"); // the rest of the JS code will be here }); }); </script> Now, create a series with the choropleth() function and the loaded data. For the coloring, let’s set up a linear color scale with four different shades of blue based on the colors on the royal website. As per convention, the darker the shade of a country, the higher the number of visits to that region. JavaScript // create a choropleth series let series = map.choropleth(dataSet); // set the map colors series .colorScale( anychart.scales.linearColor("#f2f2f2", "#42a5f5", "#1976d2", "#233580") ); Finally, give a title to the map, set the container, and draw the resulting map. JavaScript // set the map title map.title("State Visits Made by Queen Elizabeth II"); // set the container map.container('container'); // initiate the map drawing map.draw(); And voila! A beautiful and functional choropleth map is ready! Check out how it looks. You can find the entire code below or view and play with it here. HTML <html> <head> <title>JavaScript Choropleth Map</title> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-base.min.js"></script> <script data-fr-src="https://cdn.anychart.com/releases/8.11.0/js/anychart-map.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/geodata/custom/world/world.js"></script> <style type="text/css"> html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="container"></div> <script> anychart.onDocumentReady(function () { // load data from a json file anychart.data.loadJsonFile( "https://gist.githubusercontent.com/shacheeswadia/8f45da54d9bf2032fee201dbfc79e0e4/raw/5d10d58f40b4a1d994cef36dbc64545ef90ead80/queenVisits.json", function (data) { // create a dataset let dataSet = anychart.data.set(data); // create a map instance let map = anychart.map(); // set the geodata map.geoData("anychart.maps.world"); // create a choropleth series let series = map.choropleth(dataSet); // set the map colors series .colorScale( anychart.scales.linearColor("#f2f2f2", "#42a5f5", "#1976d2", "#233580") ); // set the map title map.title("State Visits Made by Queen Elizabeth II"); // set the container map.container("container"); // initiate the map drawing map.draw(); } ); }); </script> </body> </html> How to Customize a Choropleth Map The existing choropleth map is already impressive, but let me show you how to make it even more insightful and engaging! In the following steps, I'll demonstrate how you can customize the choropleth map to add more visual appeal and interactivity: Modify the colors by hovering over map areas. Add a color legend. Improve the tooltip and the title format. Add zoom controls. 1. Modify the Colors by Hovering Over the Areas You can make the map more visually appealing by modifying the colors of the hovered regions. By default, hovered regions become gray, but you can change this to a darker shade of the base color to make it more intuitive. This can be achieved by changing the fill color of the region when it is hovered and using the darken() function. JavaScript series .hovered() .fill(function (d) { return anychart.color.darken(d.sourceColor, 0.2); }); 2. Add a Color Legend Adding a color legend to your choropleth map is always a great idea, as it can help your audience understand the values and colors used in the map. To add a color legend, you only need to enable the color range. This will automatically create a legend that represents what color indicates what value. By default, the color range is disabled. To enable it, you just need to add a few lines of code: JavaScript map.colorRange() .enabled(true); And voila! You now have a beautiful and informative color legend to complement your choropleth map. 3. Improve the Tooltip and Title Format Let's take the choropleth map to the next level by improving the tooltip and the title format. Tooltips are a powerful way to showcase additional information, and they can be made even better by enabling HTML for customizing the tooltip and formatting the value. I thought it would be nice to add a custom text and indicate how many times the Queen visited the hovered country. Additionally, the specific case of the United Kingdom can be handled to showcase that the Queen lived there. With these changes, the tooltip is not only more informative but also more visually appealing. The users will enjoy the playful tone of the tooltip while learning interesting facts about the Queen's travels. JavaScript series .tooltip() .useHtml(true) .format(function (d) { if (d.name == "United Kingdom") { return "<h6 style='font-size:14px; font-weight:400; margin: 0.2rem 0;'>The Queen lived here.</h6>"; } else { return ( "<h6 style='font-size:14px; font-weight:400; margin: 0.2rem 0;'>The Queen visited <b>" + d.value + "</b> times.</h6>" ); } }); In addition to customizing the tooltip, why not enhance the chart title using HTML? For example, a subtitle will provide more context, and custom text styling will make it all shine. JavaScript map .title() .enabled(true) .useHtml(true) .text( '<span style="color: #c8102e; font-size:18px;">State visits made by Queen Elizabeth II</span>' + <span style="font-size: 15px;">(The Queen is the most widely travelled head of state in history)</span>' ); 4. Add Zoom Controls Adding zoom controls to a world map can be a great way to allow users to zoom into specific areas of interest. To get started, add the required scripts and CSS links to your HTML document's <head> section. Once you have done this, you can create the zoom controls and render them on the map with just a few lines of code. HTML <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-exports.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-ui.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/releases/8.11.0/css/anychart-ui.min.css"> <link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/releases/8.11.0/fonts/css/anychart-font.min.css"> JavaScript var zoomController = anychart.ui.zoom(); zoomController.render(map); It's worth noting that the zoom feature can be particularly useful when working with large and detailed choropleth maps. In this case, it can be a great way to allow users to explore specific regions or areas of interest in more detail. And now, just sit back and admire your beautiful JavaScript choropleth map! With the addition of customized colors, a color legend, improved tooltips and titles, and zoom controls, it’s an interactive and engaging visualization that is sure to impress. See the complete code for this project below, and feel free to play with it and see the choropleth map’s full interactive version live here. HTML <html> <head> <title>JavaScript Choropleth Map</title> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-base.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-map.min.js"></script> <script src="https://cdn.anychart.com/releases/8.11.0/geodata/custom/world/world.js"></script> <style type="text/css"> html, body, #container { width: 100%; height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="container"></div> <script> anychart.onDocumentReady(function () { // load data from a json file anychart.data.loadJsonFile( "https://gist.githubusercontent.com/shacheeswadia/8f45da54d9bf2032fee201dbfc79e0e4/raw/5d10d58f40b4a1d994cef36dbc64545ef90ead80/queenVisits.json", function (data) { // create a dataset let dataSet = anychart.data.set(data); // create a map instance let map = anychart.map(); // set the geodata map.geoData("anychart.maps.world"); // create a choropleth series let series = map.choropleth(dataSet); // set the map colors series.colorScale( anychart.scales.linearColor("#f2f2f2", "#42a5f5", "#1976d2", "#233580") ); // customize the colors in the hovered state series.hovered().fill(function (d) { return anychart.color.darken(d.sourceColor, 0.2); }); // create the map legend map.colorRange().enabled(true); // create zoom controls let zoomController = anychart.ui.zoom(); zoomController.render(map); // customize the tooltip text series .tooltip() .useHtml(true) .format(function (d) { if (d.name == "United Kingdom") { return "<h6 style='font-size:14px; font-weight:400; margin: 0.2rem 0;'>The Queen lived here.</h6>"; } else { return ( "<h6 style='font-size:14px; font-weight:400; margin: 0.2rem 0;'>The Queen visited <b>" + d.value + "</b> times.</h6>" ); } }); // set the map title map .title() .enabled(true) .useHtml(true) .text( '<span style = "color: #c8102e; font-size:18px;">State Visits Made by Queen Elizabeth II</span>' + '<br/><span style="font-size: 15px;">The Queen is the most widely traveled head of state in history</span>' ); // set the container map.container("container"); // initiate the map drawing map.draw(); } ); }); </script> </body> </html> Conclusion Сhoropleth maps are a powerful tool for visualizing data on a geographic scale. Using JavaScript, you can create stunning interactive ones that communicate complex information in a clear and concise manner. Whether you're tracking the travels of a monarch or visualizing the spread of a pandemic, the possibilities are endless. So, let your imagination run wild and start exploring the world through the lens of data!

By Shachee Swadia
React Helpful Hints Series: Volume 1
React Helpful Hints Series: Volume 1

At Solution Street, we love helping our clients solve their business problems through technology. When it comes to building responsive, dynamic web applications, we are big fans of the React ecosystem. React is a popular JavaScript framework that was developed by Facebook and has gained a massive following among developers due to its simplicity, modularity, and reusability. In this series of short “bloglets” our team will cover a wide array of React topics, including developer tips, issues, and experiences. We are hopeful that everyone from the beginner to the seasoned professional will find something useful in each post. And if you’re looking to build an amazing web application, we at Solution Street would enjoy talking with you and seeing how we can help! React Candidates: Beware These Common Mistakes! By Jeff Schuman At Solution Street, we hire great candidates with all manner of skills around the Software Development Life Cycle. In the process, we interview front-end developers and, quite often, React developers. Our process involves the candidate doing a (gentle) live-coding exercise. We do our best to make the candidate comfortable and set them up for success, presenting a well-thought-out, descriptive exercise, enabling them to use their own development machine/IDE, and providing encouragement and positive feedback. Having conducted these interviews for years, I thought it would be good to share some common mistakes candidates make during this coding exercise: Not Understanding .Map() And How To Use It When Generating React Components Understanding the JavaScript .map() function is key. In its simplest form, the .map() function iterates over a JavaScript array and returns a new array one for each item in the original array: In the context of React components, .map() is commonly used to iterate over a list of objects and render a component for each of the items in the list. Take a look at its sample use in the Catalog component below when rendering each CatalogItem: Not Breaking the Problem Down Into Components This one is (admittedly) a bit subjective. An interview is a candidate’s chance to demonstrate their expertise and experience with React, including an understanding of its component-based approach to User Interfaces. When presented with our exercise, we make clear that we are interested in seeing how the candidate “breaks down” the problem into appropriate components. However, some candidates solve our exercise by adding ALL of their code to our top-level App.js component. While this is certainly a viable solution, it doesn’t demonstrate the candidate’s ability to separate concerns, manipulate state, pass props, etc. It’s a missed opportunity for the candidate. Misunderstanding State Manipulation Regardless of whether you use class-based components or functional components, there is a key tenet with regard to state management in a component: You should not change objects that you hold in the React state directly. This is where knowledge of the .map() function — see above — or spread syntax is helpful. See the example(s) below. Not good: Better: In conclusion, we’re big fans of React at Solution Street. When we interview candidates, we enjoy discussing their experience and joy in using the React framework to build sophisticated web applications. As a candidate, it is important to know both the fundamental concepts of React AND the common idioms when designing a React application. Reduce Redundant React Re-Renders, Really! By Jared Mohney As developers, despite our most wonderful efforts, sometimes our components re-render more often than they need to. This leads to unnecessary work for our user’s browser, negatively affecting their experience! Today we’ll quickly look at two hooks that React provides — useMemo and useCallback — that can help ease these woes. useMemo The useMemo hook memoizes a value: re-computing it only when its dependencies change. This can be useful when calculating a value that takes a long time to compute (async, computationally expensive, etc.) or is used in multiple places within a component. Here with useMemo, we will not recompute expensiveToComputeValue unless a or b has changed, protecting our user from a poor experience. useCallback The useCallback hook memoizes a function, re-creating it only when its dependencies change. This can be useful when passing a function down to a child component that relies on referential equality to prevent unnecessary re-renders. Here when MyComponent re-renders, handleClick is not re-created, thereby not affecting any components downstream of it (button). TIP: As with all things, moderation! Profile your page performance and ensure you’re seeing gains worth the added complexity. Conclusion Unnecessary re-rendering is a solved problem. With a close eye and purposeful application, useMemo and useCallback stand to make our applications more performant and enjoyable to use. React Portals: When You Need a React Component To Render Somewhere Else By Adam Boudion Every once in a while, in front-end development, we find ourselves needing something to be on top of everything else. Toast messages, modals, and tooltips are the most common examples of this. Sounds conceptually pretty simple, right? We just find a way to make sure it has the biggest z-index. But sometimes, weird stuff happens. Consider the following code: Seems simple enough. We press a button, and we get a toaster message. Easy Peasy. Let’s run it and see the result. Wait a second…What’s it doing under there? … Ah, looks like the header has an enormous z-index, and it’s interfering with the appearance of our toaster. Now, in this simplistic example, we could just refactor a little bit to squash this bug, but in more complex codebases, this type of refactoring can carry risks of causing regressions or introducing new issues. So what’s a developer to do? Enter the React Portal. React Portals allow you to render child components outside of their parent’s DOM hierarchy while preserving all of its standard react behaviors and relationships, such as props and context. This is because a Portal can “move” a child component to be a descendant of any viable node in the DOM tree while having it be unchanged in the React tree. Let’s make a little change to our toaster's render method. The createPortal method takes in two arguments. The first argument is any valid renderable React child, and the second argument is any valid DOM element that you wish to become the new parent of the first argument in the DOM. Perfect! Now it visually “pops out” as we intended. As we can see, the toaster is also rendered as a child of the body in the DOM. Though not appropriate in all situations, portals were added to React for use cases just like this to add a powerful tool in the battle against rogue styling issues.

By Joel Nylund CORE

Top JavaScript Experts

expert thumbnail

Anthony Gore

Founder,
Vue.js Developers

I'm Anthony Gore and I'm here to teach you Vue.js! Through my books, online courses, and social media, my aim is to turn you into a Vue.js expert. I'm a Vue Community Partner, curator of the weekly Vue.js Developers Newsletter, and the founder of vuejsdevelopers.com, an online community for web professionals who love Vue.js. Curious about Vue? Take my free 30-minute "Vue.js Crash Course" to learn what Vue is, what kind of apps you can build with it, how it compares to React & Angular, and more. Enroll for free! https://courses.vuejsdevelopers.com/p/vue-js-crash-course?utm_source=dzone&utm_medium=bio
expert thumbnail

John Vester

Lead Software Engineer,
Marqeta @JohnJVester

Information Technology professional with 30+ years expertise in application design and architecture, feature development, project management, system administration and team supervision. Currently focusing on enterprise architecture/application design utilizing object-oriented programming languages and frameworks. Prior expertise building (Spring Boot) Java-based APIs against React and Angular client frameworks. CRM design, customization and integration with Salesforce. Additional experience using both C# (.NET Framework) and J2EE (including Spring MVC, JBoss Seam, Struts Tiles, JBoss Hibernate, Spring JDBC).
expert thumbnail

Justin Albano

Software Engineer,
IBM

I am devoted to continuously learning and improving as a software developer and sharing my experience with others in order to improve their expertise. I am also dedicated to personal and professional growth through diligent studying, discipline, and meaningful professional relationships. When not writing, I can be found playing hockey, practicing Brazilian Jiu-jitsu, watching the NJ Devils, reading, writing, or drawing. ~II Timothy 1:7~ Twitter: @justinmalbano
expert thumbnail

Swizec Teller

CEO,
preona

I'm a writer, programmer, web developer, and entrepreneur. Preona is my current startup that began its life as the team developing Twitulater. Our goal is to create a set of applications for the emerging Synaptic Web, which would rank real-time information streams in near real time, all along reading its user behaviour and understanding how to intelligently react to it. twitter: @Swizec

The Latest JavaScript Topics

article thumbnail
React Helpful Hints Series: Volume 2
In this series of short “bloglets” our team will cover a wide array of React topics, including developer tips, issues, and experiences.
June 9, 2023
by Joel Nylund CORE
· 1,813 Views · 2 Likes
article thumbnail
Superior Stream Processing: Apache Flink's Impact on Data Lakehouse Architecture
Apache Flink's unique streaming and fault tolerance features make it a strong choice for efficient data lakehouse implementation.
June 8, 2023
by Andrey Gusarov
· 2,643 Views · 2 Likes
article thumbnail
How To Create Progress Bar and Progress Spinner Using Prime React/ Prime Faces in React JS
In this article, we learned how to create a React project, set Prime React UI, and create React Js Progress Bar, Progress Spinner, and Prime React UI components.
June 7, 2023
by abhishek saini
· 1,849 Views · 1 Like
article thumbnail
How To Avoid “Schema Drift”
This article will explain the existing solutions and strategies to mitigate the challenge and avoid schema drift, including data versioning using LakeFS.
February 3, 2023
by Yaniv Ben Hemo
· 8,093 Views · 3 Likes
article thumbnail
Stateful Stream Processing With Memphis and Apache Spark
In this article, readers will use a tutorial to learn how to use Apache Spark on AWS S3 to process and enrich large scale data, including code and images.
March 14, 2023
by Sveta Gimpelson
· 5,658 Views · 1 Like
article thumbnail
A React Frontend With Go/Gin/Gorm Backend in One Project
In this article, the reader will learn more about how to build a Go Project with React Frontend and a PostgreSQL database.
June 2, 2023
by Sven Loesekann
· 3,799 Views · 3 Likes
article thumbnail
Using Render Log Streams to Log to Papertrail
We’ll look at how we can configure an app that is hosted on Render to send its system logs to Papertrail by using Render Log Streams.
June 1, 2023
by Tyler Hawkins CORE
· 3,450 Views · 1 Like
article thumbnail
Angular Unit Testing With Karma and Jasmine
Jasmine is a JavaScript testing framework, and Karma is a node-based testing tool for JavaScript codes across multiple real browsers.
June 1, 2023
by Haresh Kumbhani
· 2,813 Views · 1 Like
article thumbnail
JavaScript Temperature Anomaly Chart
Learn how to create a JS Temperature Anomaly Chart that you can use for anomaly weather and temperature scientific research using high-performance JS charts.
June 1, 2023
by Omar Urbano
· 3,045 Views · 1 Like
article thumbnail
How To Integrate the Stripe Payment Gateway Into a React Native Application
This post speaks about the various methodologies for Stripe payment gateway integration into a React Native application.
June 1, 2023
by Parija Rangnekar
· 3,188 Views · 1 Like
article thumbnail
What Is React? A Complete Guide
React is a popular JavaScript library for building user interfaces. This comprehensive guide explains React's key concepts, such as components, JSX, state, props, virtual DOM, lifecycle methods, and hooks.
May 28, 2023
by Saurabh Kumar
· 3,651 Views · 1 Like
article thumbnail
Automating the Migration From JS to TS for the ZK Framework
Migrate the JavaScript codebase for the ZK framework to TypeScript with automated tools like jscodeshift, typescript-eslint, AST Explorer, and the TSDoc parser.
May 26, 2023
by Gordon Hsu
· 5,770 Views · 4 Likes
article thumbnail
Cypress Tutorial: A Comprehensive Guide With Examples and Best Practices
Level up your automation testing skills with our comprehensive Cypress Testing tutorial. Don't miss out on the opportunity to master this powerful tool.
May 24, 2023
by Sarah Elson
· 3,352 Views · 1 Like
article thumbnail
Why You Should Consider Using React Router V6: An Overview of Changes
The latest version of React-router (v6) was released in November 2021 and marked a significant API change.
May 24, 2023
by Beste Bayhan
· 4,473 Views · 1 Like
article thumbnail
Creating a Choropleth Map With JavaScript
Learn to create a choropleth map with JavaScript step by step in this tutorial, with Queen Elizabeth II's state visits as an example of data.
May 9, 2023
by Shachee Swadia
· 4,101 Views · 3 Likes
article thumbnail
Migrating Sencha EXTJS to ReactJS
Migrate from Sencha EXTJS to ReactJS in a few, simple steps.
October 14, 2019
by Shital Agarwal
· 10,522 Views · 3 Likes
article thumbnail
Migrating a Vue.js App to Vuex
Curious about Vue's application data store? Read on to learn how to move your exiting Vue.js project to Vuex, and get an expert's opinion on what this does.
Updated February 4, 2020
by Anthony Gore CORE
· 9,793 Views · 5 Likes
article thumbnail
MiBand 3 and React Native (Part Two)
See this developer's journey creating a React Native app with MiBand 3.
Updated October 31, 2019
by Alex K
· 13,409 Views · 6 Likes
article thumbnail
Making Your SSR Sites 42x Faster With Redis Cache
Let's look at how you can leverage Redis Cache with Node.JS and Express
May 5, 2022
by Johnny Simpson CORE
· 6,945 Views · 8 Likes
article thumbnail
Learn MVC Using Angular Idle
Have you ever been logged out of a web application due to inactivity? In this tutorial, we learn how to create this functionality using an Angular library.
June 22, 2017
by Thiruppathi Rengasamy CORE
· 8,438 Views · 2 Likes
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • ...
  • Next

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: