Key Guidelines to Continuous Integration and Jenkins CI Server

This article was originally published on TestProject — Test Automation Blog. Looking for more on Jenkins and continuous integration? Check out these great links: Screencast: Which Continuous Integration Tools Support Bitbucket? Preparing and Building a PHP Project in Jenkins Continuous Integration with Jenkins Re-Introducing Jenkins: Automated Testing with Pipelines Installing and Securing Jenkins Modern software […]

Continue reading %Key Guidelines to Continuous Integration and Jenkins CI Server%


Source: Sitepoint

Hello, Laravel? Communicating with PHP through SMS!

In this article, we will modify our Laravel-powered phone-capable weather forecast app so that it is accessible via SMS (text message) in addition to the voice telephone system. It is recommended you read the previous post if you haven’t done so yet – it’s a 10 minute read for an excellent outcome.

Note: If you’re confused by the development environment we’re using, it’s Homestead Improved and you can learn more about it here, or go in detail by buying our book about PHP environments.

Vector icon of phone with weather icon overlaid

Adding Routes

To allow for SMS communication, we need some more routes. Open up the routes/web.php file and append the following code to it:

Route::group(['prefix' => 'sms', 'middleware' => 'twilio'], function () {
    Route::post('weather', 'SmsController@showWeather')->name('weather');
});

The prefix for the route is sms, so that routes will have a path like /sms/weather, as the one in the example. This is the only route we need for SMS, as Twilio will call the same route over and over again. Twilio will access it via HTTP POST. We could also do this without the prefix, but it’s more flexible this way if we decide to add more functionality to the SMS side later.

Service Layer

Next, we’ll modify the service we wrote previously. Open up the app/Services/WeatherService.php file and remove the current getWeather method, then replace it with the one below:

    public function getWeather($zip, $dayName, $forSms = false)
    {

        $point = $this->getPoint($zip);
        $tz = $this->getTimeZone($point);
        $forecast = $this->retrieveNwsData($zip);
        $ts = $this->getTimestamp($dayName, $zip);

        $tzObj = new DateTimeZone($tz->timezoneId);

        $tsObj = new DateTime(null, $tzObj);
        $tsObj->setTimestamp($ts);

        foreach ($forecast->properties->periods as $k => $period) {
            $startTs = strtotime($period->startTime);
            $endTs = strtotime($period->endTime);

            if ($ts > $startTs and $ts < $endTs) {
                $day = $period;
                break;
            }
        }

        $weather = $day->name;
        $weather .= ' the ' . $tsObj->format('jS') . ': ';

        $response = new Twiml();

        if ($forSms) {
            $remainingChars = 140 - strlen($weather);

            if (strlen($day->detailedForecast) > $remainingChars) {
                $weather .= $day->shortForecast;
                $weather .= '. High of ' . $day->temperature . '. ';
                $weather .= $day->windDirection;
                $weather .= ' winds of ' . $day->windSpeed;
            } else {
                $weather .= $day->detailedForecast;
            }

            $response->message($weather);
        } else {
            $weather .= $day->detailedForecast;

            $gather = $response->gather(
                [
                    'numDigits' => 1,
                    'action' => route('day-weather', [], false)
                ]
            );

            $menuText = ' ';
            $menuText .= "Press 1 for Sunday, 2 for Monday, 3 for Tuesday, ";
            $menuText .= "4 for Wednesday, 5 for Thursday, 6 for Friday, ";
            $menuText .= "7 for Saturday. Press 8 for the credits. ";
            $menuText .= "Press 9 to enter in a new zipcode. ";
            $menuText .= "Press 0 to hang up.";

            $gather->say($weather . $menuText);
        }

        return $response;
    }

This function is very similar to the old one. The only difference is that it takes into consideration that the weather request might be coming form a telephone device via SMS, so it makes sure that the weather forecast isn’t too long and tries to limit it to less than 140 characters. The response for SMS is still TwiML, just formatted for SMS.

Continue reading %Hello, Laravel? Communicating with PHP through SMS!%


Source: Sitepoint

Refactor Code in Your Lunch Break: Getting Started with Codemods

Maintaining a codebase can be a frustrating experience for any developer, especially a JavaScript codebase. With ever-changing standards, syntax, and third party package breaking changes, it can be hard to keep up.

In recent years, the JavaScript landscape has changed beyond recognition. Advancements in the core JavaScript language has meant that even the simplest simple task of variable declaration has been changed. ES6 introduced let and const, arrow functions, and many more core changes, each bringing improvements and benefits to developers and their applications.

Pressure on developers to produce and maintain code that will stand up to the test of time is on the increase. This article will show you how you can automate large-scale refactoring tasks with the use of codemods and the JSCodeshift tool, allowing you to easily update your code to take advantage of newer language features, for example.

Codemod

Codemod is a tool developed by Facebook to help with the refactor of large-scale codebases. It enables the developer to refactor a large codebase in a small amount of time. In some cases, a developer might use an IDE to perform the refactor of a class or variable name, however, this is usually scoped to one file at a time. The next tool in a developer’s refactoring tool kit is a global find and replace. This can work in many cases with the use of complex regular expressions. Many scenarios are not suited to this method; for example, when there are multiple implementations that need to be changed.

Codemod is a Python tool that takes a number of parameters including the expression you wish to match and the replacement.

codemod -m -d /code/myAwesomeSite/pages --extensions php,html 
    '<font *color="?(.*?)"?>(.*?)</font>' 
    '<span style="color: ;"></span>'

In the above example, we are replacing the usage of the <font> tag with a span and inlining the color style. The first two parameters are flags to indicate multiple line matching (-m) and the directory to start processing from (-d /code/myAwesomeSite/pages). We can also restrict the extensions that are processed (–extensions php,html). We then supply the match expression and the replacement. If the replacement is not provided we will be prompted for one at runtime. The tool works, but it is very similar to existing regular expression matching tools.

JSCodeshift

JSCodeshift is the next step up in the refactor toolkit. Also developed by Facebook, its a tool for running codemods across multiple files. As a Node module, JSCodeshift provides a clean and easy-to-use API, and uses Recast under the hood. Recast is an AST-to-AST (Abstract Syntax Tree) transformation tool.

Recast

Recast is a Node module that exposes an interface for parsing and reprinting JavaScript code. It can parse code in string format and generates an object from this which follows an AST structure. This allows us to inspect the code for patterns such as a function declarations.

var recast = require("recast");

var code = [
    "function add(a, b) {",
    "  return a + b",
    "}"
].join("n");

var ast = recast.parse(code);
console.log(ast);
//output
{
    "program": {
        "type": "Program",
        "body": [
            {
                "type": "FunctionDeclaration",
                "id": {
                    "type": "Identifier",
                    "name": "add",
                    "loc": {
                        "start": {
                            "line": 1,
                            "column": 9
                        },
                        "end": {
                            "line": 1,
                            "column": 12
                        },
                        "lines": {},
                        "indent": 0
                    }
                },
        ...........    

As we can see from the above example, we pass in the code string for a function that adds two numbers. When we parse and log the object we can see the AST. We see the FunctionDeclaration and the name of the function etc. As this is just a JavaScript object we can modify it as we see fit. Then we can trigger the print function to return the updated code string.

AST (Abstract Syntax Tree)

As mentioned before, Recast builds an AST from our code string. An AST is a tree representation of the abstract syntax of source code. Each node of the tree represents a construct in the source code and the node provides important information about the construct. ASTExplorer is a browser-based tool that can help to parse and understand the tree of your code.

Using ASTExplorer we can view the AST of a simple code example. Starting with our code, we will declare a const called foo and this will equal the string of ‘bar’.

const foo = 'bar';

This results in the below AST:

Screenshot of the resulting AST

We can see the VariableDeclaration under the body array, which contains our const. All VariableDeclarations have an id attribute that contains our important information such as name etc. If we were building a codemod to rename all instances of foo we can use this name attribute and iterate over all the instances to change the name.

Continue reading %Refactor Code in Your Lunch Break: Getting Started with Codemods%


Source: Sitepoint

How to Apply CSS3 Transforms to Background Images

CSS3 Transforms on Background Images

Updated version of article published on September 27, 2012. Updates include latest data on current browser support, removing unnecessary vendor prefixes from code samples, and addition of live demo on CodePen.

Scaling, skewing and rotating any element is possible with the CSS3 transform property. It’s supported in all modern browsers without vendor prefixes. If you need to support Blackberry Browser and UC Browser for Android, you’ll need to use the -webkit- prefix, e.g.

[code language=”css”]
#myelement {
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
[/code]

Great stuff. However, this rotates the whole element — its content, border and background image. What if you only want to rotate the background image? Or what if you want the background to remain fixed while the element is rotated?

Currently, there’s no W3C proposal for background-image transformations. It would be incredibly useful so I suspect one will appear eventually, but that doesn’t help developers who want to use similar effects today.

Fortunately, there is a solution. In essence, it’s a hack which applies the background image to a before or after pseudo element rather than the parent container. The pseudo element can then be transformed independently.

Transforming the Background Only

The container element can have any styles applied but it must be set to position: relative since our pseudo element will be positioned within it. You should also set overflow: hidden unless you’re happy for the background to spill out beyond the container.

[code language=”css”]
#myelement {
position: relative;
overflow: hidden;
}
[/code]

We can now create an absolutely-positioned pseudo element with a transformed background. The z-index is set to -1 to ensure it appears below the container’s content.

[code language=”css”]
#myelement:before {
content: “”;
position: absolute;
width: 200%;
height: 200%;
top: -50%;
left: -50%;
z-index: -1;
background: url(background.png) 0 0 repeat;
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
[/code]

Note you may need to adjust the pseudo element’s width, height and position. For example, if you’re using a repeated image, a rotated area must be larger than its container to fully cover the background:

CSS3 transformation on background

Fixing the Background on a Transformed Element

Continue reading %How to Apply CSS3 Transforms to Background Images%


Source: Sitepoint

Adding a Contextual Help Tab to Custom Post Type Screens

That little “Help” tab that sits in the top-right corner of the WordPress admin dashboard which, when clicked, reveals helpful information about the various admin pages and how they work is referred to as a contextual help tab. It is contextual because the information it displays pertains to the admin page that is currently being […]

Continue reading %Adding a Contextual Help Tab to Custom Post Type Screens%


Source: Sitepoint

How to Build a Virtual Design Team with 99designs

99designs is an on-demand marketplace where companies seek to find their dream design by running design contests (anything from business cards, to logos, to websites…I could go on). Many companies also use 99designs to curate their own on-call virtual design team. Think: The Avengers, but for teams of super-designers handpicked by you.

Projects” is useful for large or unexpected campaigns with tight deadlines, where agencies have the benefit of being able to access the best talent — quickly, easily, and securely. Let’s take a look at how that works exactly.

Step 1: Discovering Designers

Finding your dream designer (or dream team of designers) is the first step. Begin by navigating to /discover (link in the menu), where you’ll see an endless list of stunning designs. Your designer is here, somewhere. Let’s find them.

Discovering new designers

Next, click “Show Filters” (on the right-hand side) so that we can narrow our search a little bit — these filters are instrumental in refining the relevancy of your search result. We’re getting closer, our first designer isn’t too far away.

How to find a designer

Let’s see how smart these filters are:

  • Categories: choose which type of designs you need (you can choose anything from book covers to Facebook covers!)
  • Industries: many designers specialise in a certain industry (i.e. restaurants, technology, cosmetics and beauty, etc)
  • Search: add specific keywords to your search
  • Advanced: narrow your search even further by finding designers that speak a specific language, or specifically limit your options to Platinum designers, or those have won contests

Platinum designers are those that have been handpicked by 99designs. These are designers that have won numerous design contests and have demonstrated the highest caliber of conceptual thought and technical execution. Platinum designers go far beyond generic designs, and have a thorough understanding of typography, visual hierarchy, composition and colour, and use these skills to meet the client’s specific needs. These guys are like the Captain America’s of design teams.

Activating the search filters

When you’ve discovered a design that you like (you’ll probably find several, actually!), click on it to find out who the designer is. From here you can read about the story behind the design itself (the best designers talk about their work passionately, and with plenty of enthusiasm!) and also view the designer’s profile.

Viewing a designer's profile

You don’t need to be a detective to learn more about the designer — use the tabs on the left-hand side to see more of their work, what experience they have in certain fields, read reviews from previous clients, and finally, browse through the list of pre-made design packages that the designer offers. It’s really, really easy — and pleasantly transparent.

Viewing a designer's portfolio

Step 2: Building Your Virtual Design Team

When you think you’ve matched with the right designer, click the “Invite to work” button (on the right-hand side), where you’ll either be able to choose one of those pre-made packages, or discuss your custom needs. Alternatively, click the favourite icon (next to the designer’s name) to add them to your favourites, where you can then reach out at a later date.

Continue reading %How to Build a Virtual Design Team with 99designs%


Source: Sitepoint

Top Ten New Development Tools of the Month, June 2017

Top Ten New Development Tools of the Month

You can never have enough tools. There’s always a better way to achieve the same result no matter how slick your development process becomes!

Welcome to a new, regular series of articles that list the top ten new development tools of the month, as collated by StackShare. StackShare uses a combination of community feedback from discussions, favorites, up-votes, and stacks (tool collections) to determine the popularity of each new tool.


Looking for more on development tools or resources for learning development? Check out these great links:


The top ten new development tools for June 2017 are:

1. osquery – OS SQL Query Tool

At number #1 is osquery – a new tool from Facebook which exposes your Windows, macOS or Linux operating system as a relational database. You can use SQL queries to examine running processes, view installed software, discover hardware events and more.

The following example returns a list of attached USB hardware devices:

select * from usb_devices;

It’s an unusual idea. It could be used by web developers to monitor performance or security breaches regardless of where an application is hosted or their experience of that platform.

More information and downloads: osquery.io

2. Standup – Progress Reporting Service

Standup processes your project data from services including GitHub, Bitbucket, GitLab, Jira and Trello to create development team progress reports in a single view. The online service is free to use, easy to understand, and could streamline your daily stand-up meetings.

More information and sign-up: getstandup.com

3. Draft – Container Development Tool

Draft is an experimental tool which helps developers build applications that run on Kubernetes containers. It’s currently available on Linux and macOS, with Windows builds coming soon.

More information and downloads: github.com/Azure/draft

Continue reading %Top Ten New Development Tools of the Month, June 2017%


Source: Sitepoint

How to Create Interactive JavaScript Charts from Custom Data Sets

Charts are a great way of visualizing complex data quickly and effectively. Whether you want to identify a trend, highlight a relationship, or make a comparison, charts help you communicate with your audience in a precise and meaningful manner.

In my previous article — Getting Started with AnyChart: 10 Practical Examples — I introduced the AnyChart library and demonstrated how it is a great fit for your data visualization needs. Today, I want to dig a little deeper and look at AnyChart’s data mapping features which allow you to create beautiful charts from custom data sets with a minimum of fuss.

I also want to look at the many ways you can customize AnyChart to suit your requirements, as well as how you can change the look and feel of AnyChart charts by using themes. There are currently 17 out-of-the-box themes to choose from, or you can create your own. And if you’ve not got the best eye for design, why not buy our book to get a leg up.

As the Head of R&D at AnyChart, I could spend all day talking about this library, but now it’s time to get down to business.

Data Mapping in AnyChart

To facilitate the integration of custom data sources into charting applications, AnyChart has special objects called data sets. These objects act as intermediate containers for data. When data is stored in data sets, AnyChart can track changes to it, analyze it, and work with this data in a more robust and effective manner. In short: interactive JavaScript charts have never been easier!

No matter if you have an array of objects, an array of arrays, or a .csv file, you can use data sets to:

  • ensure full and explicit control over the series created
  • define which column is an argument (x-axis)
  • define which columns hold values for which series
  • filter data
  • sort data

Basics of Data Mapping

The best way to learn how data mapping works in AnyChart is to look at an example. Let’s imagine an array with the following custom data set:

var rawData = [
  ["A", 5, 4, 5, 8, 1, "bad"],
  ["B", 7, 1, 7, 9, 2, "good"],
  ["C", 9, 3, 5, 4, 3, "normal"],
  ["D", 1, 4, 9, 2, 4, "bad"]
];

There’s nothing too wild going on here — this kind of custom data structure is common in a lot of existing applications. But now you want to use this array in AnyChart. With many other charting libraries you would be forced to transform the data to a format that the library can work with. Well, with AnyChart things are a lot simpler — just look what we can do. First, load the array into a data set:

var rawData = [
  ["A", 5, 4, 5, 8, 1, "bad"],
  ["B", 7, 1, 7, 9, 2, "good"],
  ["C", 9, 3, 5, 4, 3, "normal"],
  ["D", 1, 4, 9, 2, 4, "bad"]
];

var dataSet = anychart.data.set(rawData);

And then, once the data has been loaded into the data set, the real magic begins: you can now create so called views. These are data sets derived from other data sets.

var rawData = [
  ["A", 5, 4, 5, 8, 1, "bad"],
  ["B", 7, 1, 7, 9, 2, "good"],
  ["C", 9, 3, 5, 4, 3, "normal"],
  ["D", 1, 4, 9, 2, 4, "bad"]
];

var dataSet = anychart.data.set(rawData);

var view1 = dataSet.mapAs({x: 0, value: 1});
var view2 = dataSet.mapAs({x: 0, value: 2});
var view3 = dataSet.mapAs({x: 0, high: 3, low: 4});
var view4 = dataSet.mapAs({x: 0, value: 5, meta: 6});

You’ll notice that when defining a view, you determine which columns from the original array are included and what names these columns get. You can then use them to create whichever kind of charts you like. For example, here’s how to create a pie chart from the custom data in the 5th column.

Note: AnyChart needs only x and value fields to create a pie chart, but the views also contain a meta field with the data from the 6th column. You can map any number of optional fields and use them as you like. For example, these fields can contain additional data to be shown as labels or as tooltips:

anychart.onDocumentLoad(function() {
  var rawData = [
    ["A", 5, 4, 5, 8, 3, "Bad"],
    ["B", 7, 1, 7, 9, 5, "Good"],
    ["C", 9, 3, 5, 4, 4, "Normal"],
    ["D", 1, 4, 9, 2, 3, "Bad"]
  ];

  var dataSet = anychart.data.set(rawData);
  var view4 = dataSet.mapAs({x: 0, value: 5, meta: 6});

  // create chart
  var chart = anychart.pie(view4);
  chart.title("AnyChart: Pie Chart from Custom Data Set");
  chart.labels().format("{%meta}: {%Value}");
  chart.container("container").draw();
});

And this is what we end up with:

See the Pen AnyChart Pie Chart from Data Set by SitePoint (@SitePoint) on CodePen.

Note: You can find all of the demos in this article as a CodePen collection.

Multi-Series Combination Chart with Custom Data Set

Now, let’s see how we can use the same custom data to create a combination chart with line and range area charts on the same plot. This section is going to be very short since now you know what views are. All you need to do is choose the proper views and create the necessary series explicitly:

anychart.onDocumentLoad(function() {
  var rawData = [
    ["A", 5, 4, 5, 8, 3, "Bad"],
    ["B", 7, 1, 7, 9, 5, "Good"],
    ["C", 9, 3, 5, 4, 4, "Normal"],
    ["D", 1, 4, 9, 2, 3, "Bad"]
  ];

  var dataSet = anychart.data.set(rawData);

  var view1 = dataSet.mapAs({x: 0, value: 1});
  var view2 = dataSet.mapAs({x: 0, value: 2});
  var view3 = dataSet.mapAs({x: 0, high: 3, low: 4});

  // create chart
  var chart = anychart.line();
  // create two line series
  chart.line(view1).name("EUR");
  chart.line(view2).name("USD");
  // create range area series
  chart.line(view2).name("Trend");

  // set title and draw chart
  chart.title("AnyChart: Combined Chart from Data Set");
  chart.container("container").draw();
});

This is what it looks like:

See the Pen AnyChart Combined Chart from Data Set by SitePoint (@SitePoint) on CodePen.

Continue reading %How to Create Interactive JavaScript Charts from Custom Data Sets%


Source: Sitepoint

How I Built a Pure CSS Crossword Puzzle

CSS Crossword Puzzle

Recently I created a pure CSS crossword puzzle implemented using CSS grid that does not need JavaScript in order to work. It gained heavy interest pretty quickly on CodePen. As of this writing, it has more than 350 hearts and 24,000+ page views!

The great CSS Grid Garden tutorial inspired me to build something with Grid Layout features. I wondered if these features could be put to good use in building a crossword puzzle — then I thought, let’s try to create the whole thing without using JavaScript.

Building the Board/Grid

So, first thing’s first, let’s create the board itself!

I ended up with the following basic structure, with HTML comments included to show what the different sections will accomplish:

[code language=”html”]
<div class=”crossword-board-container”>

<div class=”crossword-board”>

<!– input elements go here. Uses CSS Grid as its layout –>

<div class=”crossword-board crossword-board–highlight crossword-board–highlight–across”>
<!– highlights for valid ‘across’ answers go here. Uses CSS Grid as its layout –>
</div>

<div class=”crossword-board crossword-board–highlight crossword-board–highlight-down”>
<!– highlights for valid ‘down’ answers go here. Uses CSS Grid as its layout –>
</div>

<div class=”crossword-board crossword-board–labels”>
<!– row and column number labels go here. Uses CSS Grid as its layout –>
</div>

<div class=”crossword-clues”>

<dl class=”crossword-clues__list crossword-clues__list–across”>
<!– clues for all the ‘across’ words go here –>
</dl>

<dl class=”crossword-clues__list crossword-clues__list–down”>
<!– clues for all the ‘down’ words go here –>
</dl>

</div>

</div>

</div>
[/code]

That puts our basic skeleton in place so we can add more elements and start styling things.

Using Form Elements for the Squares

The crossword puzzle I’m creating is a 13×13 grid with 44 blank spaces so I need to create 125 input elements each with its own ID in the format item{row number}-{column number}, i.e. item4-12. Here’s what the grid will look like:

Empty crossword

Each of the inputs will get have a minlength and maxlength of “1” to emulate the behaviour of a crossword puzzle (i.e. one letter per square). Each input will also have the required attribute so that HTML5 form validation will be used. I take advantage of all of these HTML5 attributes using CSS.

Using the General Sibling Selector

The input elements are visually laid out in groups (exactly how a crossword puzzle is). Each group of input elements represents a word in the crossword. If each of the elements in that group is valid (which can be verified using the :valid pseudo selector), then we can use CSS to style an element that appears later in the DOM (using an advanced CSS selector called the general sibling selector) that will indicate that the word is correct.

Due to how sibling selectors work, and how CSS works in general, this element has to appear later in the DOM. CSS can only style elements that are after the currently selected element. It cannot look backwards in the DOM (or up the DOM tree) and style something before the current element (at the moment at least anyway).

This means I can use the :valid pseudo-class to style valid elements:

[code language=”css”]
.input:valid {
border: 2px solid green;
}
.input:invalid {
border: 2px solid red;
}
[/code]

See the Pen Valid Pseudo Selector Example by SitePoint (@SitePoint) on CodePen.

To style an element later on in the DOM that is a sibling of another element, I can use the ~ (tilde/general sibling) selector, e.g. A ~ B. This selector will select all elements that match B, that are a sibling of A and appear after A in the DOM. For example:

[code language=”css”]
#input1:valid ~ #input2:valid ~ #input3:valid ~ #input4:valid ~ #input5:valid ~ .valid-message {
display: block;
}
[/code]

With this code, if all these input elements are valid, the valid-message element will be displayed.

See the Pen Using Sibling Selector to Display a Message by SitePoint (@SitePoint) on CodePen.

The general sibling selector is extremely useful here. To make the crossword work, I needed to make sure that everything was laid out in a way that allowed me to take advantage of the general sibling selector.

Continue reading %How I Built a Pure CSS Crossword Puzzle%


Source: Sitepoint

What Is Snapshot Testing, and Is It Viable in PHP?

A vector image of a polaroid glued to a transparent background

Ah-ha moments are beautiful and rare in programming. Every so often, we’re fortunate enough to discover some trick or facet of a system that forever changes how we think of it.

For me, that’s what snapshot testing is.

You probably write a lot of PHP code, but today I want to talk about something I learned in JavaScript. We’ll learn about what snapshot testing is and then see how it can help us write better PHP applications.

Building Interfaces

Let’s talk about React. Not the kick-ass async PHP project, but the kick-ass JavaScript project. It’s an interface-generation tool in which we define what our interface markup should look like as discrete parts:

function Tweet(props) {
  return (
    <div className="tweet">
      <img src={props.user.avatar} />
      <div className="text">
        <div className="handle">{props.user.handle}</div>
        <div className="content">{props.content}</div>
      </div>
    </div>
  )
}

function Tweets(props) {
  return (
    <div className="tweets">
      {props.tweets.map((tweet, i) => {
        return (
          <Tweet {...tweet} key={i} />
        )
      })}
    </div>
  )
}

This doesn’t look like vanilla Javascript, but rather an unholy mix of HTML and Javascript. It’s possible to create React components using regular Javascript syntax:

function Tweet(props) {
  return React.createElement(
    "div",
    { className: "tweet" },
    React.createElement("img", { src: props.user.avatar }),
    React.createElement(
      "div",
      { className: "text" },
      React.createElement(
        "div",
        { className: "handle" },
        props.user.handle
      ),
      React.createElement(
        "div",
        { className: "content" },
        props.content
      )
    )
  );
}

To make this code, I pasted the Tweet function (above) into the Babel REPL. That’s what all React code is reduced to (minus the occasional optimization) before being executed by a browser.

Before I talk about why this is cool, I want to address a couple of issues…

“Why Are You Mixing HTML and Javascript?!”

We’ve spent a lot of time teaching and learning that markup shouldn’t be mixed with logic. It’s usually couched in the phrase “Separation of Concerns”. Thing is, splitting HTML and the Javascript which makes and manipulates that HTML is largely without value.

Splitting that markup and Javascript isn’t so much separation of concerns as it is separation of technologies. Pete Hunt talks about this in more depth in this video.

“This Syntax Is Very Strange”

That may be, but it is entirely possible to reproduce in PHP and works out the box in Hack:

class :custom:Tweet extends :x:element {
  attribute User user;
  attribute string content;

  protected function render() {
    return (
      <div class="tweet">
        <img src={$this->:user->avatar} />
        <div class="text">
          <div class="handle">{$this->:user->handle}</div>
          <div class="content">{$this->:content}</div>
        </div>
      </div>
    );
  }
}

I don’t want to in detail about this wild syntax except to say that this syntax is already possible. Unfortunately, it appears the official XHP module only supports HHVM and old versions of PHP…

Testing Interfaces

There are many testing approaches – some more effective than others. An effective way to test interface code is by faking (or making) a web request and inspecting the output for the presence and content of specific elements.

Perhaps you’ve heard of things like Selenium and Behat? I don’t want to dwell too much on them. Let’s just say that Selenium is a tool we can use to pretend to be a browser, and Behat is a business-friendly language for scripting such pretense.

Unfortunately, a lot of browser-based testing can be brittle. It’s tied to the exact structure of markup, and not necessarily related to the logic that generates the markup.

Snapshot testing is a different approach to doing the same thing. React encourages thinking about the whole interface in terms of the smallest pieces it can be broken down into. Instead of building the whole shopping cart, it encourages breaking things up into discrete parts; like:

  • each product
  • the list of products
  • the shipping details
  • the progress indicator

In building each of these pieces, we define what the markup and styles should be, given any initial information. We define this by creating a render method:

class Tweets extends React.Component {
  render() {
    return (
      <div className="tweets">
        {props.tweets.map((tweet, i) => {
          return (
            <Tweet {...tweet} key={i} />
          )
        })}
      </div>
    )
  }
}

…or by defining a plain function which will return a string or React.Component. The previous examples demonstrated the functional approach.

This is an interesting way of thinking about an interface. We write render as though it’ll only be called once, but React is constantly reconciling changes to the initial information, and the component’s own internal data.

And it’s this way of thinking that leads to the simplest way to test React components: Snapshot Testing. Think about it for a minute…

We build React components to render themselves, given any initial information. We can work through all possible inputs in our head. We can even define strict validation for what initial information (or properties) we allow into our components.

Continue reading %What Is Snapshot Testing, and Is It Viable in PHP?%


Source: Sitepoint